17
17
import { UserRecord , CreateRequest , UpdateRequest } from './user-record' ;
18
18
import { FirebaseApp } from '../firebase-app' ;
19
19
import { FirebaseTokenGenerator , CryptoSigner , cryptoSignerFromApp } from './token-generator' ;
20
- import { FirebaseAuthRequestHandler } from './auth-api-request' ;
20
+ import {
21
+ AbstractAuthRequestHandler , AuthRequestHandler , TenantAwareAuthRequestHandler ,
22
+ } from './auth-api-request' ;
21
23
import { AuthClientErrorCode , FirebaseAuthError , ErrorInfo } from '../utils/error' ;
22
24
import { FirebaseServiceInterface , FirebaseServiceInternalsInterface } from '../firebase-service' ;
23
25
import {
@@ -32,6 +34,7 @@ import {
32
34
AuthProviderConfig , AuthProviderConfigFilter , ListProviderConfigResults , UpdateAuthProviderRequest ,
33
35
SAMLConfig , OIDCConfig , OIDCConfigServerResponse , SAMLConfigServerResponse ,
34
36
} from './auth-config' ;
37
+ import { TenantManager } from './tenant-manager' ;
35
38
36
39
37
40
/**
@@ -72,6 +75,7 @@ export interface DecodedIdToken {
72
75
iat : number ;
73
76
iss : string ;
74
77
sub : string ;
78
+ tenant ?: string ;
75
79
[ key : string ] : any ;
76
80
}
77
81
@@ -85,7 +89,7 @@ export interface SessionCookieOptions {
85
89
/**
86
90
* Base Auth class. Mainly used for user management APIs.
87
91
*/
88
- class BaseAuth {
92
+ export class BaseAuth < T extends AbstractAuthRequestHandler > {
89
93
protected readonly tokenGenerator : FirebaseTokenGenerator ;
90
94
protected readonly idTokenVerifier : FirebaseTokenVerifier ;
91
95
protected readonly sessionCookieVerifier : FirebaseTokenVerifier ;
@@ -94,14 +98,14 @@ class BaseAuth {
94
98
* The BaseAuth class constructor.
95
99
*
96
100
* @param {string } projectId The corresponding project ID.
97
- * @param {FirebaseAuthRequestHandler } authRequestHandler The RPC request handler
101
+ * @param {T } authRequestHandler The RPC request handler
98
102
* for this instance.
99
103
* @param {CryptoSigner } cryptoSigner The instance crypto signer used for custom token
100
104
* minting.
101
105
* @constructor
102
106
*/
103
107
constructor ( protected readonly projectId : string ,
104
- protected readonly authRequestHandler : FirebaseAuthRequestHandler ,
108
+ protected readonly authRequestHandler : T ,
105
109
cryptoSigner : CryptoSigner ) {
106
110
this . tokenGenerator = new FirebaseTokenGenerator ( cryptoSigner ) ;
107
111
this . sessionCookieVerifier = createSessionCookieVerifier ( projectId ) ;
@@ -599,11 +603,126 @@ class BaseAuth {
599
603
}
600
604
601
605
606
+ /**
607
+ * The tenant aware Auth class.
608
+ */
609
+ export class TenantAwareAuth extends BaseAuth < TenantAwareAuthRequestHandler > {
610
+ public readonly tenantId : string ;
611
+
612
+ /**
613
+ * The TenantAwareAuth class constructor.
614
+ *
615
+ * @param {object } app The app that created this tenant.
616
+ * @param tenantId The corresponding tenant ID.
617
+ * @constructor
618
+ */
619
+ constructor ( private readonly app : FirebaseApp , tenantId : string ) {
620
+ super (
621
+ utils . getProjectId ( app ) ,
622
+ new TenantAwareAuthRequestHandler ( app , tenantId ) ,
623
+ cryptoSignerFromApp ( app ) ) ;
624
+ utils . addReadonlyGetter ( this , 'tenantId' , tenantId ) ;
625
+ }
626
+
627
+ /**
628
+ * Creates a new custom token that can be sent back to a client to use with
629
+ * signInWithCustomToken().
630
+ *
631
+ * @param {string } uid The uid to use as the JWT subject.
632
+ * @param {object= } developerClaims Optional additional claims to include in the JWT payload.
633
+ *
634
+ * @return {Promise<string> } A JWT for the provided payload.
635
+ */
636
+ public createCustomToken ( uid : string , developerClaims ?: object ) : Promise < string > {
637
+ // This is not yet supported by the Auth server. It is also not yet determined how this will be
638
+ // supported.
639
+ return Promise . reject (
640
+ new FirebaseAuthError ( AuthClientErrorCode . UNSUPPORTED_TENANT_OPERATION ) ) ;
641
+ }
642
+
643
+ /**
644
+ * Verifies a JWT auth token. Returns a Promise with the tokens claims. Rejects
645
+ * the promise if the token could not be verified. If checkRevoked is set to true,
646
+ * verifies if the session corresponding to the ID token was revoked. If the corresponding
647
+ * user's session was invalidated, an auth/id-token-revoked error is thrown. If not specified
648
+ * the check is not applied.
649
+ *
650
+ * @param {string } idToken The JWT to verify.
651
+ * @param {boolean= } checkRevoked Whether to check if the ID token is revoked.
652
+ * @return {Promise<DecodedIdToken> } A Promise that will be fulfilled after a successful
653
+ * verification.
654
+ */
655
+ public verifyIdToken ( idToken : string , checkRevoked : boolean = false ) : Promise < DecodedIdToken > {
656
+ return super . verifyIdToken ( idToken , checkRevoked )
657
+ . then ( ( decodedClaims ) => {
658
+ // Validate tenant ID.
659
+ if ( decodedClaims . firebase . tenant !== this . tenantId ) {
660
+ throw new FirebaseAuthError ( AuthClientErrorCode . MISMATCHING_TENANT_ID ) ;
661
+ }
662
+ return decodedClaims ;
663
+ } ) ;
664
+ }
665
+
666
+ /**
667
+ * Creates a new Firebase session cookie with the specified options that can be used for
668
+ * session management (set as a server side session cookie with custom cookie policy).
669
+ * The session cookie JWT will have the same payload claims as the provided ID token.
670
+ *
671
+ * @param {string } idToken The Firebase ID token to exchange for a session cookie.
672
+ * @param {SessionCookieOptions } sessionCookieOptions The session cookie options which includes
673
+ * custom session duration.
674
+ *
675
+ * @return {Promise<string> } A promise that resolves on success with the created session cookie.
676
+ */
677
+ public createSessionCookie (
678
+ idToken : string , sessionCookieOptions : SessionCookieOptions ) : Promise < string > {
679
+ // Validate arguments before processing.
680
+ if ( ! validator . isNonEmptyString ( idToken ) ) {
681
+ return Promise . reject ( new FirebaseAuthError ( AuthClientErrorCode . INVALID_ID_TOKEN ) ) ;
682
+ }
683
+ if ( ! validator . isNonNullObject ( sessionCookieOptions ) ||
684
+ ! validator . isNumber ( sessionCookieOptions . expiresIn ) ) {
685
+ return Promise . reject ( new FirebaseAuthError ( AuthClientErrorCode . INVALID_SESSION_COOKIE_DURATION ) ) ;
686
+ }
687
+ // This will verify the ID token and then match the tenant ID before creating the session cookie.
688
+ return this . verifyIdToken ( idToken )
689
+ . then ( ( decodedIdTokenClaims ) => {
690
+ return super . createSessionCookie ( idToken , sessionCookieOptions ) ;
691
+ } ) ;
692
+ }
693
+
694
+ /**
695
+ * Verifies a Firebase session cookie. Returns a Promise with the tokens claims. Rejects
696
+ * the promise if the token could not be verified. If checkRevoked is set to true,
697
+ * verifies if the session corresponding to the session cookie was revoked. If the corresponding
698
+ * user's session was invalidated, an auth/session-cookie-revoked error is thrown. If not
699
+ * specified the check is not performed.
700
+ *
701
+ * @param {string } sessionCookie The session cookie to verify.
702
+ * @param {boolean= } checkRevoked Whether to check if the session cookie is revoked.
703
+ * @return {Promise<DecodedIdToken> } A Promise that will be fulfilled after a successful
704
+ * verification.
705
+ */
706
+ public verifySessionCookie (
707
+ sessionCookie : string , checkRevoked : boolean = false ) : Promise < DecodedIdToken > {
708
+ return super . verifySessionCookie ( sessionCookie , checkRevoked )
709
+ . then ( ( decodedClaims ) => {
710
+ if ( decodedClaims . firebase . tenant !== this . tenantId ) {
711
+ throw new FirebaseAuthError ( AuthClientErrorCode . MISMATCHING_TENANT_ID ) ;
712
+ }
713
+ return decodedClaims ;
714
+ } ) ;
715
+ }
716
+ }
717
+
718
+
602
719
/**
603
720
* Auth service bound to the provided app.
721
+ * An Auth instance can have multiple tenants.
604
722
*/
605
- export class Auth extends BaseAuth implements FirebaseServiceInterface {
723
+ export class Auth extends BaseAuth < AuthRequestHandler > implements FirebaseServiceInterface {
606
724
public INTERNAL : AuthInternals = new AuthInternals ( ) ;
725
+ private readonly tenantManager_ : TenantManager ;
607
726
private readonly app_ : FirebaseApp ;
608
727
609
728
/**
@@ -629,9 +748,10 @@ export class Auth extends BaseAuth implements FirebaseServiceInterface {
629
748
constructor ( app : FirebaseApp ) {
630
749
super (
631
750
Auth . getProjectId ( app ) ,
632
- new FirebaseAuthRequestHandler ( app ) ,
751
+ new AuthRequestHandler ( app ) ,
633
752
cryptoSignerFromApp ( app ) ) ;
634
753
this . app_ = app ;
754
+ this . tenantManager_ = new TenantManager ( app ) ;
635
755
}
636
756
637
757
/**
@@ -642,4 +762,9 @@ export class Auth extends BaseAuth implements FirebaseServiceInterface {
642
762
get app ( ) : FirebaseApp {
643
763
return this . app_ ;
644
764
}
765
+
766
+ /** @return The current Auth instance's tenant manager. */
767
+ public tenantManager ( ) : TenantManager {
768
+ return this . tenantManager_ ;
769
+ }
645
770
}
0 commit comments