Skip to content

fixed iat error of 1 second earlier #21

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 3 commits into from
Dec 29, 2024
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
7 changes: 4 additions & 3 deletions src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@ export class BaseAuth {
* @param env - An optional parameter specifying the environment in which the function is running.
* If the function is running in an emulator environment, this should be set to `EmulatorEnv`.
* If not specified, the function will assume it is running in a production environment.
*
* @param clockSkewSeconds - The number of seconds to tolerate when checking the `iat`.
* This is to deal with small clock differences among different servers.
* @returns A promise fulfilled with the
* token's decoded claims if the ID token is valid; otherwise, a rejected
* promise.
*/
public async verifyIdToken(idToken: string, checkRevoked = false, env?: EmulatorEnv): Promise<FirebaseIdToken> {
public async verifyIdToken(idToken: string, checkRevoked = false, env?: EmulatorEnv, clockSkewSeconds?: number): Promise<FirebaseIdToken> {
const isEmulator = useEmulator(env);
const decodedIdToken = await this.idTokenVerifier.verifyJWT(idToken, isEmulator);
const decodedIdToken = await this.idTokenVerifier.verifyJWT(idToken, isEmulator, clockSkewSeconds);
// Whether to check if the token was revoked.
if (checkRevoked) {
return await this.verifyDecodedJWTNotRevokedOrDisabled(decodedIdToken, AuthClientErrorCode.ID_TOKEN_REVOKED, env);
Expand Down
16 changes: 12 additions & 4 deletions src/token-verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,23 +226,31 @@ export class FirebaseTokenVerifier {
*
* @param jwtToken - The Firebase Auth JWT token to verify.
* @param isEmulator - Whether to accept Auth Emulator tokens.
* @param clockSkewSeconds - The number of seconds to tolerate when checking the token's iat. Must be between 0-60, and an integer. Defualts to 0.
* @returns A promise fulfilled with the decoded claims of the Firebase Auth ID token.
*/
public verifyJWT(jwtToken: string, isEmulator = false): Promise<FirebaseIdToken> {
public verifyJWT(jwtToken: string, isEmulator = false, clockSkewSeconds: number = 5): Promise<FirebaseIdToken> {
if (!isString(jwtToken)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`First argument to ${this.tokenInfo.verifyApiName} must be a ${this.tokenInfo.jwtName} string.`
);
}
return this.decodeAndVerify(jwtToken, isEmulator).then(payload => {

if (clockSkewSeconds < 0 || clockSkewSeconds > 60 || !Number.isInteger(clockSkewSeconds)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
'clockSkewSeconds must be an integer between 0 and 60.'
)
}
return this.decodeAndVerify(jwtToken, isEmulator, clockSkewSeconds).then(payload => {
payload.uid = payload.sub;
return payload;
});
}

private async decodeAndVerify(token: string, isEmulator: boolean): Promise<FirebaseIdToken> {
const currentTimestamp = Math.floor(Date.now() / 1000);
private async decodeAndVerify(token: string, isEmulator: boolean, clockSkewSeconds: number = 5): Promise<FirebaseIdToken> {
const currentTimestamp = Math.floor(Date.now() / 1000) + clockSkewSeconds;
try {
const rs256Token = this.safeDecode(token, isEmulator, currentTimestamp);
const { payload } = rs256Token.decodedToken;
Expand Down