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