Skip to content

feat: Moved the credential APIs under firebase-admin/app #1137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions etc/firebase-admin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ export namespace app {
}
}

// @public (undocumented)
export function applicationDefault(httpAgent?: Agent): Credential;

// @public
export interface AppOptions {
credential?: credential.Credential;
credential?: Credential;
databaseAuthVariableOverride?: object | null;
databaseURL?: string;
httpAgent?: Agent;
Expand Down Expand Up @@ -396,14 +399,20 @@ export namespace auth {
}
}

// @public (undocumented)
export function cert(serviceAccountPathOrObject: string | ServiceAccount, httpAgent?: Agent): Credential;

// @public (undocumented)
export interface Credential {
getAccessToken(): Promise<GoogleOAuthAccessToken>;
}

// @public (undocumented)
export namespace credential {
export function applicationDefault(httpAgent?: Agent): Credential;
export function cert(serviceAccountPathOrObject: string | ServiceAccount, httpAgent?: Agent): Credential;
export interface Credential {
getAccessToken(): Promise<GoogleOAuthAccessToken>;
}
export function refreshToken(refreshTokenPathOrObject: string | object, httpAgent?: Agent): Credential;
export type Credential = Credential;
const applicationDefault: typeof applicationDefault;
const cert: typeof cert;
const refreshToken: typeof refreshToken;
}

// @public
Expand Down Expand Up @@ -930,6 +939,9 @@ export namespace projectManagement {
}
}

// @public (undocumented)
export function refreshToken(refreshTokenPathOrObject: string | object, httpAgent?: Agent): Credential;

// @public
export function remoteConfig(app?: app.App): remoteConfig.RemoteConfig;

Expand Down
6 changes: 3 additions & 3 deletions src/app/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@

import { Agent } from 'http';

import { credential } from '../credential/index';
import { Credential } from './credential';

/**
* Available options to pass to [`initializeApp()`](admin#.initializeApp).
*/
export interface AppOptions {

/**
* A {@link credential.Credential `Credential`} object used to
* A {@link Credential `Credential`} object used to
* authenticate the Admin SDK.
*
* See [Initialize the SDK](/docs/admin/setup#initialize_the_sdk) for detailed
* documentation and code samples.
*/
credential?: credential.Credential;
credential?: Credential;

/**
* The object to use as the [`auth`](/docs/reference/security/database/#auth)
Expand Down
24 changes: 17 additions & 7 deletions src/credential/credential.ts → src/app/credential-factory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*!
* @license
* Copyright 2017 Google Inc.
* Copyright 2021 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,35 +15,45 @@
* limitations under the License.
*/

import { Agent } from 'http';

import { Credential, ServiceAccount } from './credential';
import {
ServiceAccountCredential, RefreshTokenCredential, getApplicationDefault
} from './credential-internal';
import { credential } from './index';

let globalAppDefaultCred: credential.Credential;
let globalAppDefaultCred: Credential | undefined;
const globalCertCreds: { [key: string]: ServiceAccountCredential } = {};
const globalRefreshTokenCreds: { [key: string]: RefreshTokenCredential } = {};

export const applicationDefault: typeof credential.applicationDefault = (httpAgent?) => {
export function applicationDefault(httpAgent?: Agent): Credential {
if (typeof globalAppDefaultCred === 'undefined') {
globalAppDefaultCred = getApplicationDefault(httpAgent);
}
return globalAppDefaultCred;
}

export const cert: typeof credential.cert = (serviceAccountPathOrObject, httpAgent?) => {
export function cert(serviceAccountPathOrObject: string | ServiceAccount, httpAgent?: Agent): Credential {
const stringifiedServiceAccount = JSON.stringify(serviceAccountPathOrObject);
if (!(stringifiedServiceAccount in globalCertCreds)) {
globalCertCreds[stringifiedServiceAccount] = new ServiceAccountCredential(serviceAccountPathOrObject, httpAgent);
globalCertCreds[stringifiedServiceAccount] = new ServiceAccountCredential(
serviceAccountPathOrObject, httpAgent);
}
return globalCertCreds[stringifiedServiceAccount];
}

export const refreshToken: typeof credential.refreshToken = (refreshTokenPathOrObject, httpAgent) => {
export function refreshToken(refreshTokenPathOrObject: string | object, httpAgent?: Agent): Credential {
const stringifiedRefreshToken = JSON.stringify(refreshTokenPathOrObject);
if (!(stringifiedRefreshToken in globalRefreshTokenCreds)) {
globalRefreshTokenCreds[stringifiedRefreshToken] = new RefreshTokenCredential(
refreshTokenPathOrObject, httpAgent);
}
return globalRefreshTokenCreds[stringifiedRefreshToken];
}

/**
* Clears the global ADC cache. Exported for testing.
*/
export function clearGlobalAppDefaultCred(): void {
globalAppDefaultCred = undefined;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*!
* @license
* Copyright 2020 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -19,13 +20,11 @@ import os = require('os');
import path = require('path');

import { Agent } from 'http';
import { credential, GoogleOAuthAccessToken } from './index';
import { Credential, GoogleOAuthAccessToken } from './credential';
import { AppErrorCodes, FirebaseAppError } from '../utils/error';
import { HttpClient, HttpRequestConfig, HttpError, HttpResponse } from '../utils/api-request';
import * as util from '../utils/validator';

import Credential = credential.Credential;

const GOOGLE_TOKEN_AUDIENCE = 'https://accounts.google.com/o/oauth2/token';
const GOOGLE_AUTH_TOKEN_HOST = 'accounts.google.com';
const GOOGLE_AUTH_TOKEN_PATH = '/o/oauth2/token';
Expand Down
45 changes: 45 additions & 0 deletions src/app/credential.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2021 Google Inc.
*
* 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.
*/

export interface ServiceAccount {
projectId?: string;
clientEmail?: string;
privateKey?: string;
}

/**
* Interface for Google OAuth 2.0 access tokens.
*/
export interface GoogleOAuthAccessToken {
access_token: string;
expires_in: number;
}

export interface Credential {
/**
* Returns a Google OAuth2 access token object used to authenticate with
* Firebase services.
*
* This object contains the following properties:
* * `access_token` (`string`): The actual Google OAuth2 access token.
* * `expires_in` (`number`): The number of seconds from when the token was
* issued that it expires.
*
* @return A Google OAuth2 access token object.
*/
getAccessToken(): Promise<GoogleOAuthAccessToken>;
}
5 changes: 2 additions & 3 deletions src/app/firebase-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/

import { AppOptions, app } from '../firebase-namespace-api';
import { credential, GoogleOAuthAccessToken } from '../credential/index';
import { getApplicationDefault } from '../credential/credential-internal';
import { Credential, GoogleOAuthAccessToken } from './credential';
import { getApplicationDefault } from './credential-internal';
import * as validator from '../utils/validator';
import { deepCopy } from '../utils/deep-copy';
import { FirebaseNamespaceInternals } from './firebase-namespace';
Expand All @@ -36,7 +36,6 @@ import { ProjectManagement } from '../project-management/project-management';
import { SecurityRules } from '../security-rules/security-rules';
import { RemoteConfig } from '../remote-config/remote-config';

import Credential = credential.Credential;
import Database = database.Database;

/**
Expand Down
4 changes: 2 additions & 2 deletions src/app/firebase-namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import fs = require('fs');
import { AppErrorCodes, FirebaseAppError } from '../utils/error';
import { AppOptions, app } from '../firebase-namespace-api';
import { FirebaseApp } from './firebase-app';
import { cert, refreshToken, applicationDefault } from '../credential/credential';
import { getApplicationDefault } from '../credential/credential-internal';
import { cert, refreshToken, applicationDefault } from './credential-factory';
import { getApplicationDefault } from './credential-internal';

import { auth } from '../auth/index';
import { database } from '../database/index';
Expand Down
3 changes: 3 additions & 0 deletions src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ import { getSdkVersion } from '../utils';
export { App, AppOptions } from './core'
export { initializeApp, getApp, getApps, deleteApp } from './lifecycle';

export { Credential, ServiceAccount, GoogleOAuthAccessToken } from './credential';
export { applicationDefault, cert, refreshToken } from './credential-factory';

export const SDK_VERSION = getSdkVersion();
2 changes: 1 addition & 1 deletion src/auth/token-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/

import { FirebaseApp } from '../app/firebase-app';
import { ServiceAccountCredential } from '../credential/credential-internal';
import { ServiceAccountCredential } from '../app/credential-internal';
import { AuthClientErrorCode, FirebaseAuthError } from '../utils/error';
import { AuthorizedHttpClient, HttpError, HttpRequestConfig, HttpClient } from '../utils/api-request';

Expand Down
44 changes: 11 additions & 33 deletions src/credential/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,14 @@
* limitations under the License.
*/

import { Agent } from 'http';
import {
Credential as TCredential,
applicationDefault as applicationDefaultFn,
cert as certFn,
refreshToken as refreshTokenFn,
} from '../app/index';

export interface ServiceAccount {
projectId?: string;
clientEmail?: string;
privateKey?: string;
}

/**
* Interface for Google OAuth 2.0 access tokens.
*/
export interface GoogleOAuthAccessToken {
access_token: string;
expires_in: number;
}
export { ServiceAccount, GoogleOAuthAccessToken } from '../app/index';

/* eslint-disable @typescript-eslint/no-namespace */
export namespace credential {
Expand All @@ -40,20 +33,7 @@ export namespace credential {
* use the default implementations provided by
* {@link credential `admin.credential`}.
*/
export interface Credential {
/**
* Returns a Google OAuth2 access token object used to authenticate with
* Firebase services.
*
* This object contains the following properties:
* * `access_token` (`string`): The actual Google OAuth2 access token.
* * `expires_in` (`number`): The number of seconds from when the token was
* issued that it expires.
*
* @return A Google OAuth2 access token object.
*/
getAccessToken(): Promise<GoogleOAuthAccessToken>;
}
export type Credential = TCredential;

/**
* Returns a credential created from the
Expand Down Expand Up @@ -89,7 +69,7 @@ export namespace credential {
* @return {!admin.credential.Credential} A credential authenticated via Google
* Application Default Credentials that can be used to initialize an app.
*/
export declare function applicationDefault(httpAgent?: Agent): Credential;
export const applicationDefault = applicationDefaultFn;

/**
* Returns a credential created from the provided service account that grants
Expand Down Expand Up @@ -136,8 +116,7 @@ export namespace credential {
* @return A credential authenticated via the
* provided service account that can be used to initialize an app.
*/
export declare function cert(
serviceAccountPathOrObject: string | ServiceAccount, httpAgent?: Agent): Credential;
export const cert = certFn;

/**
* Returns a credential created from the provided refresh token that grants
Expand Down Expand Up @@ -172,6 +151,5 @@ export namespace credential {
* @return A credential authenticated via the
* provided service account that can be used to initialize an app.
*/
export declare function refreshToken(
refreshTokenPathOrObject: string | object, httpAgent?: Agent): Credential;
export const refreshToken = refreshTokenFn;
}
2 changes: 1 addition & 1 deletion src/firestore/firestore-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import { FirebaseApp } from '../app/firebase-app';
import { FirebaseFirestoreError } from '../utils/error';
import { ServiceAccountCredential, isApplicationDefault } from '../credential/credential-internal';
import { ServiceAccountCredential, isApplicationDefault } from '../app/credential-internal';
import { Firestore, Settings } from '@google-cloud/firestore';

import * as validator from '../utils/validator';
Expand Down
2 changes: 1 addition & 1 deletion src/storage/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import { FirebaseApp } from '../app/firebase-app';
import { FirebaseError } from '../utils/error';
import { ServiceAccountCredential, isApplicationDefault } from '../credential/credential-internal';
import { ServiceAccountCredential, isApplicationDefault } from '../app/credential-internal';
import { Bucket, Storage as StorageClient } from '@google-cloud/storage';
import * as utils from '../utils/index';
import * as validator from '../utils/validator';
Expand Down
2 changes: 1 addition & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import { App } from '../app/index';
import {
ServiceAccountCredential, ComputeEngineCredential
} from '../credential/credential-internal';
} from '../app/credential-internal';
import * as validator from './validator';

let sdkVersion: string;
Expand Down
7 changes: 3 additions & 4 deletions test/resources/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import * as jwt from 'jsonwebtoken';
import { AppOptions } from '../../src/firebase-namespace-api';
import { FirebaseNamespace } from '../../src/app/firebase-namespace';
import { FirebaseApp } from '../../src/app/firebase-app';
import { credential as _credential, GoogleOAuthAccessToken } from '../../src/credential/index';
import { ServiceAccountCredential } from '../../src/credential/credential-internal';
import { Credential, GoogleOAuthAccessToken, cert } from '../../src/app/index';

const ALGORITHM = 'RS256' as const;
const ONE_HOUR_IN_SECONDS = 60 * 60;
Expand All @@ -51,7 +50,7 @@ export const databaseAuthVariableOverride = { 'some#string': 'some#val' };

export const storageBucket = 'bucketName.appspot.com';

export const credential = new ServiceAccountCredential(path.resolve(__dirname, './mock.key.json'));
export const credential = cert(path.resolve(__dirname, './mock.key.json'));

export const appOptions: AppOptions = {
credential,
Expand Down Expand Up @@ -80,7 +79,7 @@ export const appOptionsAuthDB: AppOptions = {
databaseURL,
};

export class MockCredential implements _credential.Credential {
export class MockCredential implements Credential {
public getAccessToken(): Promise<GoogleOAuthAccessToken> {
return Promise.resolve({
access_token: 'mock-token', // eslint-disable-line @typescript-eslint/camelcase
Expand Down
Loading