Skip to content
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

Support for creating custom tokens without service account credentials #285

Merged
merged 23 commits into from
Jul 12, 2018
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Unreleased

- [changed] Admin SDK can now create custom tokens without being initialized
with service account credentials. When a service account private key is not
available, the SDK uses the remote IAM service to sign JWTs in the cloud.
- [changed] Admin SDK can now read the Firebase/GCP project ID from both
`GCLOUD_PROJECT` and `GOOGLE_CLOUD_PROJECT` environment variables.

Expand Down
39 changes: 9 additions & 30 deletions src/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import {UserRecord, CreateRequest, UpdateRequest} from './user-record';
import {FirebaseApp} from '../firebase-app';
import {FirebaseTokenGenerator} from './token-generator';
import {FirebaseTokenGenerator, signerFromApp} from './token-generator';
import {FirebaseAuthRequestHandler} from './auth-api-request';
import {AuthClientErrorCode, FirebaseAuthError, ErrorInfo} from '../utils/error';
import {FirebaseServiceInterface, FirebaseServiceInternalsInterface} from '../firebase-service';
Expand All @@ -26,6 +26,7 @@ import {

import * as utils from '../utils/index';
import * as validator from '../utils/validator';
import { FirebaseTokenVerifier, newSessionCookieVerifier, newIdTokenVerifier } from './token-verifier';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename newSessionCookieVerifier and newIdTokenVerifier to createSessionCookieVerifier and createIdTokenVerifier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done



/**
Expand Down Expand Up @@ -84,6 +85,8 @@ export class Auth implements FirebaseServiceInterface {

private app_: FirebaseApp;
private tokenGenerator_: FirebaseTokenGenerator;
private idTokenVerifier_: FirebaseTokenVerifier;
private sessionCookieVerifier_: FirebaseTokenVerifier;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private idTokenVerifier: FirebaseTokenVerifier;
private sessionCookieVerifier: FirebaseTokenVerifier;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

private authRequestHandler: FirebaseAuthRequestHandler;

/**
Expand All @@ -99,27 +102,10 @@ export class Auth implements FirebaseServiceInterface {
}

this.app_ = app;
this.tokenGenerator_ = new FirebaseTokenGenerator(signerFromApp(app));
const projectId = utils.getProjectId(app);

// TODO (inlined): plumb this into a factory method for tokenGenerator_ once we
// can generate custom tokens from access tokens.
let serviceAccount;
if (typeof app.options.credential.getCertificate === 'function') {
serviceAccount = app.options.credential.getCertificate();
}
if (serviceAccount) {
// Cert credentials and Application Default Credentials created from a service account file
// provide a certificate we can use to mint custom tokens and verify ID tokens.
this.tokenGenerator_ = new FirebaseTokenGenerator(serviceAccount);
} else if (validator.isNonEmptyString(projectId)) {
// Google infrastructure like GAE, GCE, and GCF store the GCP / Firebase project ID in an
// environment variable that we can use to get verifyIdToken() to work. createCustomToken()
// still won't work since it requires a private key and client email which we do not have.
const cert: any = {
projectId,
};
this.tokenGenerator_ = new FirebaseTokenGenerator(cert);
}
this.sessionCookieVerifier_ = newSessionCookieVerifier(projectId);
this.idTokenVerifier_ = newIdTokenVerifier(projectId);
// Initialize auth request handler with the app.
this.authRequestHandler = new FirebaseAuthRequestHandler(app);
}
Expand Down Expand Up @@ -165,14 +151,7 @@ export class Auth implements FirebaseServiceInterface {
* verification.
*/
public verifyIdToken(idToken: string, checkRevoked: boolean = false): Promise<object> {
if (typeof this.tokenGenerator_ === 'undefined') {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_CREDENTIAL,
'Must initialize app with a cert credential or set your Firebase project ID as the ' +
'GOOGLE_CLOUD_PROJECT environment variable to call auth().verifyIdToken().',
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove this check here and not in verifySessionCookie below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this one too, and updated the error message in the verifier.

return this.tokenGenerator_.verifyIdToken(idToken)
return this.idTokenVerifier_.verifyJWT(idToken)
.then((decodedIdToken: DecodedIdToken) => {
// Whether to check if the token was revoked.
if (!checkRevoked) {
Expand Down Expand Up @@ -408,7 +387,7 @@ export class Auth implements FirebaseServiceInterface {
'GOOGLE_CLOUD_PROJECT environment variable to call auth().verifySessionCookie().',
);
}
return this.tokenGenerator_.verifySessionCookie(sessionCookie)
return this.sessionCookieVerifier_.verifyJWT(sessionCookie)
.then((decodedIdToken: DecodedIdToken) => {
// Whether to check if the token was revoked.
if (!checkRevoked) {
Expand Down
Loading