Skip to content

Commit 27e0e6f

Browse files
committed
Merge expired error code to erro code config
1 parent bba0b02 commit 27e0e6f

File tree

5 files changed

+66
-50
lines changed

5 files changed

+66
-50
lines changed

src/auth/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import * as utils from '../utils/index';
3030
import * as validator from '../utils/validator';
3131
import { auth } from './index';
3232
import { FirebaseTokenVerifier } from '../utils/token-verifier';
33-
import { createSessionCookieVerifier, createIdTokenVerifier } from './token-verifier-util';
33+
import { createSessionCookieVerifier, createIdTokenVerifier } from './token-verifier';
3434
import {
3535
SAMLConfig, OIDCConfig, OIDCConfigServerResponse, SAMLConfigServerResponse,
3636
} from './auth-config';

src/auth/token-verifier-util.ts renamed to src/auth/token-verifier.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,20 @@ const CLIENT_CERT_URL = 'https://www.googleapis.com/robot/v1/metadata/x509/secur
2727
// URL containing the public keys for Firebase session cookies. This will be updated to a different URL soon.
2828
const SESSION_COOKIE_CERT_URL = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys';
2929

30-
/** Error codes that matches the FirebaseAuthError type */
31-
const AUTH_ERROR_CODE_CONFIG: ErrorCodeConfig = {
30+
/** Matching Auth error code config for ID token */
31+
export const ID_TOKEN_ERROR_CODE_CONFIG: ErrorCodeConfig = {
3232
invalidArg: AuthClientErrorCode.INVALID_ARGUMENT,
3333
invalidCredential: AuthClientErrorCode.INVALID_CREDENTIAL,
3434
internalError: AuthClientErrorCode.INTERNAL_ERROR,
35+
expiredError: AuthClientErrorCode.ID_TOKEN_EXPIRED,
36+
}
37+
38+
/** Matching Auth error code config for session cookie */
39+
export const SESSION_COOKIE_ERROR_CODE_CONFIG: ErrorCodeConfig = {
40+
invalidArg: AuthClientErrorCode.INVALID_ARGUMENT,
41+
invalidCredential: AuthClientErrorCode.INVALID_CREDENTIAL,
42+
internalError: AuthClientErrorCode.INTERNAL_ERROR,
43+
expiredError: AuthClientErrorCode.SESSION_COOKIE_EXPIRED,
3544
}
3645

3746
/** User facing token information related to the Firebase ID token. */
@@ -40,8 +49,7 @@ export const ID_TOKEN_INFO: FirebaseTokenInfo = {
4049
verifyApiName: 'verifyIdToken()',
4150
jwtName: 'Firebase ID token',
4251
shortName: 'ID token',
43-
expiredErrorCode: AuthClientErrorCode.ID_TOKEN_EXPIRED,
44-
errorCodeConfig: AUTH_ERROR_CODE_CONFIG,
52+
errorCodeConfig: ID_TOKEN_ERROR_CODE_CONFIG,
4553
errorType: FirebaseAuthError,
4654
};
4755

@@ -51,8 +59,7 @@ export const SESSION_COOKIE_INFO: FirebaseTokenInfo = {
5159
verifyApiName: 'verifySessionCookie()',
5260
jwtName: 'Firebase session cookie',
5361
shortName: 'session cookie',
54-
expiredErrorCode: AuthClientErrorCode.SESSION_COOKIE_EXPIRED,
55-
errorCodeConfig: AUTH_ERROR_CODE_CONFIG,
62+
errorCodeConfig: SESSION_COOKIE_ERROR_CODE_CONFIG,
5663
errorType: FirebaseAuthError,
5764
};
5865

src/utils/error.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export interface ErrorCodeConfig {
4040
invalidArg: ErrorInfo;
4141
invalidCredential: ErrorInfo;
4242
internalError: ErrorInfo;
43+
expiredError: ErrorInfo;
4344
}
4445

4546
/**

src/utils/token-verifier.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ export interface FirebaseTokenInfo {
3737
jwtName: string;
3838
/** The JWT short name. */
3939
shortName: string;
40-
/** JWT Expiration error code. */
41-
expiredErrorCode: ErrorInfo;
4240
/** Error code config of the public error type. */
4341
errorCodeConfig: ErrorCodeConfig;
4442
/** Public error type. */
@@ -73,9 +71,14 @@ export class FirebaseTokenVerifier {
7371
throw new Error('The JWT public full name must be a non-empty string.');
7472
} else if (!validator.isNonEmptyString(tokenInfo.shortName)) {
7573
throw new Error('The JWT public short name must be a non-empty string.');
76-
} else if (!validator.isNonNullObject(tokenInfo.expiredErrorCode) ||
77-
!('code' in tokenInfo.expiredErrorCode)) {
78-
throw new Error('The JWT expiration error code must be a non-null ErrorInfo object.');
74+
} else if (!(typeof tokenInfo.errorType === 'function' && tokenInfo.errorType !== null)) {
75+
throw new Error('The provided error type must be a non-null PrefixedFirebaseError type.');
76+
} else if (!validator.isNonNullObject(tokenInfo.errorCodeConfig) ||
77+
!('invalidArg' in tokenInfo.errorCodeConfig ||
78+
'invalidCredential' in tokenInfo.errorCodeConfig ||
79+
'internalError' in tokenInfo.errorCodeConfig ||
80+
'expiredError' in tokenInfo.errorCodeConfig)) {
81+
throw new Error('The provided error code config must be a non-null ErrorCodeInfo object.');
7982
}
8083
this.shortNameArticle = tokenInfo.shortName.charAt(0).match(/[aeiou]/i) ? 'an' : 'a';
8184

@@ -213,9 +216,9 @@ export class FirebaseTokenVerifier {
213216
if (error) {
214217
if (error.name === 'TokenExpiredError') {
215218
const errorMessage = `${this.tokenInfo.jwtName} has expired. Get a fresh ${this.tokenInfo.shortName}` +
216-
` from your client app and try again (auth/${this.tokenInfo.expiredErrorCode.code}).` +
219+
` from your client app and try again (auth/${this.tokenInfo.errorCodeConfig.expiredError.code}).` +
217220
verifyJwtTokenDocsMessage;
218-
return reject(new this.tokenInfo.errorType(this.tokenInfo.expiredErrorCode, errorMessage));
221+
return reject(new this.tokenInfo.errorType(this.tokenInfo.errorCodeConfig.expiredError, errorMessage));
219222
} else if (error.name === 'JsonWebTokenError') {
220223
const errorMessage = `${this.tokenInfo.jwtName} has invalid signature.` + verifyJwtTokenDocsMessage;
221224
return reject(new this.tokenInfo.errorType(this.tokenInfo.errorCodeConfig.invalidArg, errorMessage));

test/unit/auth/token-verifier.spec.ts

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ import LegacyFirebaseTokenGenerator = require('firebase-token-generator');
3030
import * as mocks from '../../resources/mocks';
3131
import { FirebaseTokenGenerator, ServiceAccountSigner } from '../../../src/auth/token-generator';
3232
import * as verifier from '../../../src/utils/token-verifier';
33-
import * as verifierUtil from '../../../src/auth/token-verifier-util';
33+
import * as verifierUtil from '../../../src/auth/token-verifier';
3434

3535
import { ServiceAccountCredential } from '../../../src/credential/credential-internal';
36-
import { AuthClientErrorCode, ErrorCodeConfig, FirebaseAuthError } from '../../../src/utils/error';
36+
import { FirebaseAuthError } from '../../../src/utils/error';
3737
import { FirebaseApp } from '../../../src/firebase-app';
3838
import { Algorithm } from 'jsonwebtoken';
3939

@@ -46,12 +46,6 @@ const expect = chai.expect;
4646
const ONE_HOUR_IN_SECONDS = 60 * 60;
4747
const idTokenPublicCertPath = '/robot/v1/metadata/x509/[email protected]';
4848

49-
const AUTH_ERROR_CODE_CONFIG: ErrorCodeConfig = {
50-
invalidArg: AuthClientErrorCode.INVALID_ARGUMENT,
51-
invalidCredential: AuthClientErrorCode.INVALID_CREDENTIAL,
52-
internalError: AuthClientErrorCode.INTERNAL_ERROR,
53-
}
54-
5549
/**
5650
* Returns a mocked out success response from the URL containing the public keys for the Google certs.
5751
*
@@ -166,8 +160,7 @@ describe('FirebaseTokenVerifier', () => {
166160
verifyApiName: 'verifyToken()',
167161
jwtName: 'Important Token',
168162
shortName: 'token',
169-
expiredErrorCode: AuthClientErrorCode.INVALID_ARGUMENT,
170-
errorCodeConfig: AUTH_ERROR_CODE_CONFIG,
163+
errorCodeConfig: verifierUtil.ID_TOKEN_ERROR_CODE_CONFIG,
171164
errorType: FirebaseAuthError,
172165
},
173166
app,
@@ -232,8 +225,7 @@ describe('FirebaseTokenVerifier', () => {
232225
verifyApiName: invalidVerifyApiName as any,
233226
jwtName: 'Important Token',
234227
shortName: 'token',
235-
expiredErrorCode: AuthClientErrorCode.INVALID_ARGUMENT,
236-
errorCodeConfig: AUTH_ERROR_CODE_CONFIG,
228+
errorCodeConfig: verifierUtil.ID_TOKEN_ERROR_CODE_CONFIG,
237229
errorType: FirebaseAuthError,
238230
},
239231
app,
@@ -255,8 +247,7 @@ describe('FirebaseTokenVerifier', () => {
255247
verifyApiName: 'verifyToken()',
256248
jwtName: invalidJwtName as any,
257249
shortName: 'token',
258-
expiredErrorCode: AuthClientErrorCode.INVALID_ARGUMENT,
259-
errorCodeConfig: AUTH_ERROR_CODE_CONFIG,
250+
errorCodeConfig: verifierUtil.ID_TOKEN_ERROR_CODE_CONFIG,
260251
errorType: FirebaseAuthError,
261252
},
262253
app,
@@ -278,8 +269,7 @@ describe('FirebaseTokenVerifier', () => {
278269
verifyApiName: 'verifyToken()',
279270
jwtName: 'Important Token',
280271
shortName: invalidShortName as any,
281-
expiredErrorCode: AuthClientErrorCode.INVALID_ARGUMENT,
282-
errorCodeConfig: AUTH_ERROR_CODE_CONFIG,
272+
errorCodeConfig: verifierUtil.ID_TOKEN_ERROR_CODE_CONFIG,
283273
errorType: FirebaseAuthError,
284274
},
285275
app,
@@ -288,9 +278,9 @@ describe('FirebaseTokenVerifier', () => {
288278
});
289279
});
290280

291-
const invalidExpiredErrorCodes = [null, NaN, 0, 1, true, false, [], {}, { a: 1 }, _.noop, '', 'test'];
292-
invalidExpiredErrorCodes.forEach((invalidExpiredErrorCode) => {
293-
it('should throw given an invalid expiration error code: ' + JSON.stringify(invalidExpiredErrorCode), () => {
281+
const invalidErrorCodeTypes = [null, NaN, 0, 1, true, false, [], {}, { a: 1 }, _.noop, '', 'test'];
282+
invalidErrorCodeTypes.forEach((invalidErrorCodeType) => {
283+
it('should throw given an invalid error code config: ' + JSON.stringify(invalidErrorCodeType), () => {
294284
expect(() => {
295285
new verifier.FirebaseTokenVerifier(
296286
'https://www.example.com/publicKeys',
@@ -301,13 +291,34 @@ describe('FirebaseTokenVerifier', () => {
301291
verifyApiName: 'verifyToken()',
302292
jwtName: 'Important Token',
303293
shortName: 'token',
304-
expiredErrorCode: invalidExpiredErrorCode as any,
305-
errorCodeConfig: AUTH_ERROR_CODE_CONFIG,
294+
errorCodeConfig: verifierUtil.ID_TOKEN_ERROR_CODE_CONFIG,
295+
errorType: invalidErrorCodeTypes as any,
296+
},
297+
app,
298+
);
299+
}).to.throw('The provided error type must be a non-null PrefixedFirebaseError type.');
300+
});
301+
});
302+
303+
const invalidErrorCodeConfigs = [null, NaN, 0, 1, true, false, [], {}, { a: 1 }, _.noop, '', 'test'];
304+
invalidErrorCodeConfigs.forEach((invalidErrorCodeConfig) => {
305+
it('should throw given an invalid error code config: ' + JSON.stringify(invalidErrorCodeConfig), () => {
306+
expect(() => {
307+
new verifier.FirebaseTokenVerifier(
308+
'https://www.example.com/publicKeys',
309+
'RS256',
310+
'https://www.example.com/issuer/',
311+
{
312+
url: 'https://docs.example.com/verify-tokens',
313+
verifyApiName: 'verifyToken()',
314+
jwtName: 'Important Token',
315+
shortName: 'token',
316+
errorCodeConfig: invalidErrorCodeConfig as any,
306317
errorType: FirebaseAuthError,
307318
},
308319
app,
309320
);
310-
}).to.throw('The JWT expiration error code must be a non-null ErrorInfo object.');
321+
}).to.throw('The provided error code config must be a non-null ErrorCodeInfo object.');
311322
});
312323
});
313324
});
@@ -326,10 +337,9 @@ describe('FirebaseTokenVerifier', () => {
326337
}).to.throw('First argument to verifyIdToken() must be a Firebase ID token');
327338
});
328339

329-
const errorTypes = [
330-
{ type: FirebaseAuthError, config: AUTH_ERROR_CODE_CONFIG },
331-
];
332-
errorTypes.forEach((errorType) => {
340+
it('should throw with the correct error type and code set in token info', () => {
341+
const errorType = FirebaseAuthError;
342+
const errorCodeConfig = verifierUtil.ID_TOKEN_ERROR_CODE_CONFIG;
333343
const tokenVerifier = new verifier.FirebaseTokenVerifier(
334344
'https://www.example.com/publicKeys',
335345
'RS256',
@@ -339,19 +349,14 @@ describe('FirebaseTokenVerifier', () => {
339349
verifyApiName: 'verifyToken()',
340350
jwtName: 'Important Token',
341351
shortName: 'token',
342-
expiredErrorCode: errorType.config.invalidArg,
343-
errorCodeConfig: errorType.config,
344-
errorType: errorType.type,
352+
errorCodeConfig: errorCodeConfig,
353+
errorType,
345354
},
346355
app,
347356
);
348-
it('should throw with the correct error type and code set in token info', () => {
349-
expect(() => {
350-
(tokenVerifier as any).verifyJWT();
351-
}).to.throw(errorType.type).with.property('code').match(
352-
new RegExp(`(.*)/${errorType.config.invalidArg.code}`)
353-
);
354-
});
357+
expect(() => {
358+
(tokenVerifier as any).verifyJWT();
359+
}).to.throw(errorType).with.property('code').equal(`auth/${errorCodeConfig.invalidArg.code}`);
355360
});
356361

357362
const invalidIdTokens = [null, NaN, 0, 1, true, false, [], {}, { a: 1 }, _.noop];

0 commit comments

Comments
 (0)