-
Notifications
You must be signed in to change notification settings - Fork 25
Description
Describe the Issue
We have an authorizer lambda that validates Azure AD JWT tokens using Azure’s public keys and extracts user information (name, email, roles, groups, scope) from valid tokens. Here's a snippet of the validator class we've written:
import { setConfig, verify, VerifyOptions } from 'azure-ad-verify-token';
import { JwtPayload } from 'jsonwebtoken';
import logger from '$lib/logger';
// Cache the Microsoft public key for an hour so that we don't fetch it each time we verify a JWT
setConfig({
cacheLifetime: 60 * 60 * 1000, // 1 hour
});
type AzureConfig = {
audience: string;
tenantId: string;
};
type AzureJwtValidatorResult = {
isAuthorized: boolean;
user: string;
roles: string;
groups: string;
scope: string;
};
class AzureJwtValidator {
private readonly audience: string;
private readonly tenantId: string;
constructor(config: AzureConfig) {
this.audience = config.audience;
this.tenantId = config.tenantId;
}
private constructVerifyOptions(): VerifyOptions {
return {
jwksUri: `https://login.microsoftonline.com/${this.tenantId}/discovery/v2.0/keys`,
issuer: `https://sts.windows.net/${this.tenantId}/`,
audience: this.audience,
};
}
private buildResult(decodedToken: string | JwtPayload): AzureJwtValidatorResult {
return {
isAuthorized: true,
user: JSON.stringify({
name: decodedToken.name,
email: decodedToken.unique_name,
}),
roles: JSON.stringify(decodedToken.roles),
groups: JSON.stringify(decodedToken.groups),
scope: decodedToken.scp,
};
}
async parseToken(authorizationHeaderValue: string): Promise<AzureJwtValidatorResult> {
const token = authorizationHeaderValue.replace(/^Bearer\s+/, '');
const options = this.constructVerifyOptions();
try {
logger.debug('Calling verify with options', JSON.stringify(options));
const decodedToken = await verify(token, options);
return this.buildResult(decodedToken);
} catch (err) {
logger.error(`Failed to verify token: ${err}`);
return this.buildResult('');
}
}
}
However, with the help of debug logs, we find that calling verify(token, options) intermittently times out with the following error message:
Task timed out after 30.23 seconds
We've set the lambda time out to be longer than this, so it seems like this is not an issue related to the lambda configuration itself.
Could we rule out a network or JWKs endpoint issue? Could it be due to a token cache misconfiguration?
We are using the setConfig function to cache the Microsoft public key for 1 hour. If there is an issue with the caching mechanism (e.g., cache not being refreshed properly or invalid cache data), the verify function may hang while attempting to retrieve or validate the key.
Any feedback is greatly appreciated.
Expected behavior
Calling verify(token, options) should not intermittently time out
Steps to Reproduce
n/a
Other Information
n/a