1717import { UserRecord , CreateRequest , UpdateRequest } from './user-record' ;
1818import { FirebaseApp } from '../firebase-app' ;
1919import { FirebaseTokenGenerator , CryptoSigner , cryptoSignerFromApp } from './token-generator' ;
20- import { FirebaseAuthRequestHandler } from './auth-api-request' ;
20+ import {
21+ AbstractAuthRequestHandler , AuthRequestHandler , TenantAwareAuthRequestHandler ,
22+ } from './auth-api-request' ;
2123import { AuthClientErrorCode , FirebaseAuthError , ErrorInfo } from '../utils/error' ;
2224import { FirebaseServiceInterface , FirebaseServiceInternalsInterface } from '../firebase-service' ;
2325import {
@@ -32,6 +34,7 @@ import {
3234 AuthProviderConfig , AuthProviderConfigFilter , ListProviderConfigResults , UpdateAuthProviderRequest ,
3335 SAMLConfig , OIDCConfig , OIDCConfigServerResponse , SAMLConfigServerResponse ,
3436} from './auth-config' ;
37+ import { TenantManager } from './tenant-manager' ;
3538
3639
3740/**
@@ -72,6 +75,7 @@ export interface DecodedIdToken {
7275 iat : number ;
7376 iss : string ;
7477 sub : string ;
78+ tenant ?: string ;
7579 [ key : string ] : any ;
7680}
7781
@@ -85,7 +89,7 @@ export interface SessionCookieOptions {
8589/**
8690 * Base Auth class. Mainly used for user management APIs.
8791 */
88- class BaseAuth {
92+ export class BaseAuth < T extends AbstractAuthRequestHandler > {
8993 protected readonly tokenGenerator : FirebaseTokenGenerator ;
9094 protected readonly idTokenVerifier : FirebaseTokenVerifier ;
9195 protected readonly sessionCookieVerifier : FirebaseTokenVerifier ;
@@ -94,14 +98,14 @@ class BaseAuth {
9498 * The BaseAuth class constructor.
9599 *
96100 * @param {string } projectId The corresponding project ID.
97- * @param {FirebaseAuthRequestHandler } authRequestHandler The RPC request handler
101+ * @param {T } authRequestHandler The RPC request handler
98102 * for this instance.
99103 * @param {CryptoSigner } cryptoSigner The instance crypto signer used for custom token
100104 * minting.
101105 * @constructor
102106 */
103107 constructor ( protected readonly projectId : string ,
104- protected readonly authRequestHandler : FirebaseAuthRequestHandler ,
108+ protected readonly authRequestHandler : T ,
105109 cryptoSigner : CryptoSigner ) {
106110 this . tokenGenerator = new FirebaseTokenGenerator ( cryptoSigner ) ;
107111 this . sessionCookieVerifier = createSessionCookieVerifier ( projectId ) ;
@@ -599,11 +603,126 @@ class BaseAuth {
599603}
600604
601605
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+
602719/**
603720 * Auth service bound to the provided app.
721+ * An Auth instance can have multiple tenants.
604722 */
605- export class Auth extends BaseAuth implements FirebaseServiceInterface {
723+ export class Auth extends BaseAuth < AuthRequestHandler > implements FirebaseServiceInterface {
606724 public INTERNAL : AuthInternals = new AuthInternals ( ) ;
725+ private readonly tenantManager_ : TenantManager ;
607726 private readonly app_ : FirebaseApp ;
608727
609728 /**
@@ -629,9 +748,10 @@ export class Auth extends BaseAuth implements FirebaseServiceInterface {
629748 constructor ( app : FirebaseApp ) {
630749 super (
631750 Auth . getProjectId ( app ) ,
632- new FirebaseAuthRequestHandler ( app ) ,
751+ new AuthRequestHandler ( app ) ,
633752 cryptoSignerFromApp ( app ) ) ;
634753 this . app_ = app ;
754+ this . tenantManager_ = new TenantManager ( app ) ;
635755 }
636756
637757 /**
@@ -642,4 +762,9 @@ export class Auth extends BaseAuth implements FirebaseServiceInterface {
642762 get app ( ) : FirebaseApp {
643763 return this . app_ ;
644764 }
765+
766+ /** @return The current Auth instance's tenant manager. */
767+ public tenantManager ( ) : TenantManager {
768+ return this . tenantManager_ ;
769+ }
645770}
0 commit comments