Skip to content
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
12 changes: 12 additions & 0 deletions packages/auth-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Observer, Unsubscribe } from '@firebase/util';
export interface User extends UserInfo {
delete(): Promise<any>;
emailVerified: boolean;
getIdTokenResult(forceRefresh?: boolean): Promise<IdTokenResult>;
getIdToken(forceRefresh?: boolean): Promise<any>;
getToken(forceRefresh?: boolean): Promise<any>;
isAnonymous: boolean;
Expand Down Expand Up @@ -160,6 +161,17 @@ export class GoogleAuthProvider_Instance implements AuthProvider {
setCustomParameters(customOAuthParameters: Object): AuthProvider;
}

export interface IdTokenResult {
token: string;
expirationTime: string;
authTime: string;
issuedAtTime: string;
signInProvider: string | null;
claims: {
[key: string]: any;
};
}

export class OAuthProvider implements AuthProvider {
providerId: string;
addScope(scope: string): AuthProvider;
Expand Down
6 changes: 6 additions & 0 deletions packages/auth/demo/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,12 @@
Confirm Email Verification
</button>
</form>
<button class="btn btn-block btn-default" id="get-token-result">
Get ID Token Result (no refresh)
</button>
<button class="btn btn-block btn-default" id="refresh-token-result">
Refresh ID Token Result
</button>
<button class="btn btn-block btn-default" id="get-token">
Get ID Token (no refresh)
</button>
Expand Down
40 changes: 38 additions & 2 deletions packages/auth/demo/public/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,38 @@ function getIdToken(forceRefresh) {
}


/**
* Gets or refreshes the ID token result.
* @param {boolean} forceRefresh Whether to force the refresh of the token
* or not
*/
function getIdTokenResult(forceRefresh) {
if (activeUser() == null) {
alertError('No user logged in.');
return;
}
activeUser().getIdTokenResult(forceRefresh).then(function(idTokenResult) {
alertSuccess(JSON.stringify(idTokenResult));
}, onAuthError);
}


/**
* Triggers the retrieval of the ID token result.
*/
function onGetIdTokenResult() {
getIdTokenResult(false);
}


/**
* Triggers the refresh of the ID token result.
*/
function onRefreshTokenResult() {
getIdTokenResult(true);
}


/**
* Triggers the retrieval of the ID token.
*/
Expand Down Expand Up @@ -1271,8 +1303,10 @@ function initApp(){
auth.onIdTokenChanged(function(user) {
refreshUserData();
if (user) {
user.getIdToken(false).then(
log,
user.getIdTokenResult(false).then(
function(idTokenResult) {
log(JSON.stringify(idTokenResult));
},
function() {
log('No token.');
}
Expand Down Expand Up @@ -1382,6 +1416,8 @@ function initApp(){

$('#send-email-verification').click(onSendEmailVerification);
$('#confirm-email-verification').click(onApplyActionCode);
$('#get-token-result').click(onGetIdTokenResult);
$('#refresh-token-result').click(onRefreshTokenResult);
$('#get-token').click(onGetIdToken);
$('#refresh-token').click(onRefreshToken);
$('#get-token-worker').click(onGetCurrentUserDataFromWebWorker);
Expand Down
15 changes: 15 additions & 0 deletions packages/auth/src/authuser.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ goog.require('fireauth.AuthEventHandler');
goog.require('fireauth.AuthEventManager');
goog.require('fireauth.AuthProvider');
goog.require('fireauth.ConfirmationResult');
goog.require('fireauth.IdTokenResult');
goog.require('fireauth.PhoneAuthProvider');
goog.require('fireauth.ProactiveRefresh');
goog.require('fireauth.RpcHandler');
Expand Down Expand Up @@ -921,6 +922,20 @@ fireauth.AuthUser.prototype.reloadWithoutSaving_ = function() {
};


/**
* This operation resolves with the Firebase ID token result which contains
* the entire payload claims.
* @param {boolean=} opt_forceRefresh Whether to force refresh token exchange.
* @return {!goog.Promise<!fireauth.IdTokenResult>} A Promise that resolves with
* the ID token result.
*/
fireauth.AuthUser.prototype.getIdTokenResult = function(opt_forceRefresh) {
return this.getIdToken(opt_forceRefresh).then(function(idToken) {
return new fireauth.IdTokenResult(idToken);
});
};


/**
* This operation resolves with the Firebase ID token.
* @param {boolean=} opt_forceRefresh Whether to force refresh token exchange.
Expand Down
4 changes: 4 additions & 0 deletions packages/auth/src/exports_auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ fireauth.exportlib.exportPrototypeMethods(
name: 'delete',
args: []
},
getIdTokenResult: {
name: 'getIdTokenResult',
args: [fireauth.args.bool('opt_forceRefresh', true)]
},
getIdToken: {
name: 'getIdToken',
args: [fireauth.args.bool('opt_forceRefresh', true)]
Expand Down
22 changes: 18 additions & 4 deletions packages/auth/src/idtoken.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,23 @@ fireauth.IdToken.prototype.getPhoneNumber = function() {
* @return {?fireauth.IdToken} The decoded token.
*/
fireauth.IdToken.parse = function(tokenString) {
var token = fireauth.IdToken.parseIdTokenClaims(tokenString);
if (token && token['sub'] && token['iss'] && token['aud'] && token['exp']) {
return new fireauth.IdToken(
/** @type {!fireauth.IdToken.JsonToken} */ (token));
}
return null;
};

/**
* Converts the information part of JWT token to plain object format.
* @param {?string} tokenString The JWT token.
* @return {?Object}
*/
fireauth.IdToken.parseIdTokenClaims = function(tokenString) {
if (!tokenString) {
return null;
}
// Token format is <algorithm>.<info>.<sig>
var fields = tokenString.split('.');
if (fields.length != 3) {
Expand All @@ -187,10 +204,7 @@ fireauth.IdToken.parse = function(tokenString) {
}
try {
var token = JSON.parse(goog.crypt.base64.decodeString(jsonInfo, true));
if (token['sub'] && token['iss'] && token['aud'] && token['exp']) {
return new fireauth.IdToken(
/** @type {!fireauth.IdToken.JsonToken} */ (token));
}
return /** @type {?Object} */ (token);
} catch (e) {}
return null;
};
63 changes: 63 additions & 0 deletions packages/auth/src/idtokenresult.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright 2018 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.
*/

/**
* @fileoverview Defines the firebase.auth.IdTokenResult class that is obtained
* from getIdTokenResult. It contains the ID token JWT string and other helper
* properties for getting different data associated with the token as well as
* all the decoded payload claims.
*/

goog.provide('fireauth.IdTokenResult');

goog.require('fireauth.AuthError');
goog.require('fireauth.IdToken');
goog.require('fireauth.authenum.Error');
goog.require('fireauth.object');
goog.require('fireauth.util');



/**
* This is the ID token result object obtained from getIdTokenResult. It
* contains the ID token JWT string and other helper properties for getting
* different data associated with the token as well as all the decoded payload
* claims.
* @param {string} tokenString The JWT token.
* @constructor
*/
fireauth.IdTokenResult = function(tokenString) {
var idToken = fireauth.IdToken.parseIdTokenClaims(tokenString);
if (!idToken || !idToken['exp'] || !idToken['auth_time'] || !idToken['iat']) {
throw new fireauth.AuthError(
fireauth.authenum.Error.INTERNAL_ERROR,
'An internal error occurred. The token obtained by Firebase appears ' +
'to be malformed. Please retry the operation.');
}
fireauth.object.setReadonlyProperties(this, {
'token': tokenString,
'expirationTime': fireauth.util.utcTimestampToDateString(
idToken['exp'] * 1000),
'authTime': fireauth.util.utcTimestampToDateString(
idToken['auth_time'] * 1000),
'issuedAtTime': fireauth.util.utcTimestampToDateString(
idToken['iat'] * 1000),
'signInProvider': (idToken['firebase'] &&
idToken['firebase']['sign_in_provider']) ?
idToken['firebase']['sign_in_provider'] : null,
'claims': idToken
});
};
Loading