UNPKG

quodolores

Version:

Monorepo for the Firebase JavaScript SDK

128 lines (116 loc) 4.11 kB
/** * @license * Copyright 2020 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { IdTokenResult, ParsedToken, User } from '../../model/public_types'; import { base64Decode, getModularInstance } from '@firebase/util'; import { UserInternal } from '../../model/user'; import { _assert } from '../util/assert'; import { _logError } from '../util/log'; import { utcTimestampToDateString } from '../util/time'; import { AuthErrorCode } from '../errors'; /** * Returns a JSON Web Token (JWT) used to identify the user to a Firebase service. * * @remarks * Returns the current token if it has not expired or if it will not expire in the next five * minutes. Otherwise, this will refresh the token and return a new one. * * @param user - The user. * @param forceRefresh - Force refresh regardless of token expiration. * * @public */ export function getIdToken(user: User, forceRefresh = false): Promise<string> { return getModularInstance(user).getIdToken(forceRefresh); } /** * Returns a deserialized JSON Web Token (JWT) used to identitfy the user to a Firebase service. * * @remarks * Returns the current token if it has not expired or if it will not expire in the next five * minutes. Otherwise, this will refresh the token and return a new one. * * @param user - The user. * @param forceRefresh - Force refresh regardless of token expiration. * * @public */ export async function getIdTokenResult( user: User, forceRefresh = false ): Promise<IdTokenResult> { const userInternal = getModularInstance(user) as UserInternal; const token = await userInternal.getIdToken(forceRefresh); const claims = _parseToken(token); _assert( claims && claims.exp && claims.auth_time && claims.iat, userInternal.auth, AuthErrorCode.INTERNAL_ERROR ); const firebase = typeof claims.firebase === 'object' ? claims.firebase : undefined; const signInProvider: string | undefined = firebase?.['sign_in_provider']; return { claims, token, authTime: utcTimestampToDateString( secondsStringToMilliseconds(claims.auth_time) )!, issuedAtTime: utcTimestampToDateString( secondsStringToMilliseconds(claims.iat) )!, expirationTime: utcTimestampToDateString( secondsStringToMilliseconds(claims.exp) )!, signInProvider: signInProvider || null, signInSecondFactor: firebase?.['sign_in_second_factor'] || null }; } function secondsStringToMilliseconds(seconds: string): number { return Number(seconds) * 1000; } export function _parseToken(token: string): ParsedToken | null { const [algorithm, payload, signature] = token.split('.'); if ( algorithm === undefined || payload === undefined || signature === undefined ) { _logError('JWT malformed, contained fewer than 3 sections'); return null; } try { const decoded = base64Decode(payload); if (!decoded) { _logError('Failed to decode base64 JWT payload'); return null; } return JSON.parse(decoded); } catch (e) { _logError('Caught error parsing JWT payload as JSON', e); return null; } } /** * Extract expiresIn TTL from a token by subtracting the expiration from the issuance. */ export function _tokenExpiresIn(token: string): number { const parsedToken = _parseToken(token); _assert(parsedToken, AuthErrorCode.INTERNAL_ERROR); _assert(typeof parsedToken.exp !== 'undefined', AuthErrorCode.INTERNAL_ERROR); _assert(typeof parsedToken.iat !== 'undefined', AuthErrorCode.INTERNAL_ERROR); return Number(parsedToken.exp) - Number(parsedToken.iat); }