nebular icon indicating copy to clipboard operation
nebular copied to clipboard

IsAuthenticatedOrRefresh doesn't work with firebase

Open RezaRahmati opened this issue 4 years ago • 2 comments

Issue type

I'm submitting a ... (check one with "x")

  • [*] bug report
  • [ ] feature request

Issue description

Current behavior:

Throwing error Error: 'refreshToken' is not supported by 'NbFirebaseGoogleStrategy', use 'authenticate'

While if you autheticate without nebular with AngularFire this problem doesn't happen, and I think it could be related to this https://stackoverflow.com/a/37908468/2279488

Expected behavior:

Token doesn't expire until user signed out

Steps to reproduce:

  • enabling NbFirebaseGoogleStrategy based on documentations
  • calling this.authService.isAuthenticatedOrRefresh() in authGuard

Related code:

import { NbAuthSocialLink } from '@nebular/auth';
import { NbFirebaseGoogleStrategy, NbFirebasePasswordStrategy } from '@nebular/firebase-auth';

const socialLinks: Array<NbAuthSocialLink> = [{
	link: 'google',
	icon: 'google',
	title: 'google',
}];

export const defaultAuthSettings: any = {

	forms: {
		login: {
			strategy: 'password',
			rememberMe: true,
			socialLinks: socialLinks,
		},
		register: {
			strategy: 'password',
			terms: true,
			socialLinks: socialLinks,
		},
		logout: {
			strategy: 'password',
		},
		requestPassword: {
			strategy: 'password',
			socialLinks: socialLinks,
		},
		resetPassword: {
			strategy: 'password',
			socialLinks: socialLinks,
		},
		validation: {
			password: {
				required: true,
				minLength: 6,
				maxLength: 50,
			},
			email: {
				required: true,
			},
			fullName: {
				required: false,
				minLength: 4,
				maxLength: 50,
			},
		},
	},
	strategies: [
		NbFirebasePasswordStrategy.setup({
			name: 'password',
			login: {
				redirect: {
					success: '/',
				},
			},
			register: {
				redirect: {
					success: '/',
				},
			},
			logout: {
				redirect: {
					success: 'auth/login',
				},
			},
			requestPassword: {
				redirect: {
					success: 'auth/login',
				},
			},
			resetPassword: {
				redirect: {
					success: 'auth/login',
				},
			},
		}),
		NbFirebaseGoogleStrategy.setup({
			name: 'google',
		}),
	],
};

Other information:

npm, node, OS, Browser

<!--
Node, npm: `node --version` and `npm --version`
OS: Windows (7/8/10). Linux (incl. distribution). macOS (El Capitan? Sierra?)
Browser: Chrome/Safari/Firefox/etc?
-->

Angular, Nebular

		"@angular/animations": "~11.0.5",
		"@angular/cdk": "^11.0.3",
		"@angular/common": "~11.0.5",
		"@angular/compiler": "~11.0.5",
		"@angular/core": "~11.0.5",
		"@angular/fire": "^6.1.4",
		"@angular/forms": "~11.0.5",
		"@angular/platform-browser": "~11.0.5",
		"@angular/platform-browser-dynamic": "~11.0.5",
		"@angular/router": "~11.0.5",
		"@nebular/auth": "^7.0.0",
		"@nebular/eva-icons": "^7.0.0",
		"@nebular/firebase-auth": "^7.0.0",
		"@nebular/theme": "^7.0.0",

RezaRahmati avatar Mar 06 '21 17:03 RezaRahmati

Facing similar issue, any update on this bug report? currently on version 9.1.0-rc.8

vip20 avatar Nov 26 '22 16:11 vip20

My solution:

I extended the original class with the refresh implemented, they didn't had implemented it

import { Injectable } from '@angular/core';
import firebase from 'firebase/compat/app';
import { Observable, of as observableOf, from } from 'rxjs';
import { catchError, map, switchMap, take } from 'rxjs/operators';
import { NbAuthStrategyOptions, NbAuthStrategyClass, NbAuthResult } from '@nebular/auth';

import { NbFirebaseBaseStrategy, NbFirebaseIdentityProviderStrategyOptions } from '@nebular/firebase-auth';

@Injectable()
export class FirebaseGoogleStrategy extends NbFirebaseBaseStrategy {
    protected defaultOptions: NbFirebaseIdentityProviderStrategyOptions = new NbFirebaseIdentityProviderStrategyOptions();

    static setup(options: NbFirebaseIdentityProviderStrategyOptions): [NbAuthStrategyClass, NbAuthStrategyOptions] {
        return [FirebaseGoogleStrategy, options];
    }

    authenticate(data?: any): Observable<NbAuthResult> {
        const module = 'authenticate';
        const provider = new firebase.auth.GoogleAuthProvider();
        const scopes = this.getOption('scopes');
        scopes.forEach((scope) => provider.addScope(scope));
        provider.setCustomParameters(this.getOption('customParameters'));
    
        return from(this.afAuth.signInWithPopup(provider)).pipe(
          switchMap((res) => this.processSuccess(res, module)),
          catchError((error) => this.processFailure(error, module)),
        );
      }

    refreshToken(data?: any): Observable<NbAuthResult> {
        const module = 'refreshToken';
        return this.afAuth.authState.pipe(
            take(1),
            switchMap((user) => {
                if (user == null) {
                    return observableOf(
                        new NbAuthResult(false, null, null, [
                            "There is no logged in user so refresh of id token isn't possible",
                        ]),
                    );
                }
                return this.refreshIdToken(user, module);
            }),
        );
    }

    protected refreshIdToken(user: firebase.User, module): Observable<NbAuthResult> {
        return from(user.getIdToken(true)).pipe(
            map((token) => {
                return new NbAuthResult(
                    true,
                    null,
                    this.getOption(`${module}.redirect.success`),
                    [],
                    this.getOption(`${module}.defaultMessages`),
                    this.createToken(token),
                );
            }),
            catchError((error) => this.processFailure(error, module)),
        );
    }
}

fabio-stein avatar May 17 '23 02:05 fabio-stein