Skip to content

Commit

Permalink
feat(cognito): ✨ Control JWT timestamps via props (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShellXploit authored Apr 20, 2024
1 parent abe12aa commit 08254f3
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 7 deletions.
7 changes: 5 additions & 2 deletions src/awsServices/cognito/cognito.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const getCognitoTokens = ({
asymmetricKeys,
user,
cognito = {},
userPool = {}
userPool = {},
jwtConfig = {}
}: GetCognitoTokensProps): CognitoTokens => {
const userData = {
uuid: getUUID(),
Expand All @@ -33,7 +34,9 @@ export const getCognitoTokens = ({
const issuerUrl = getIssuerUrl(userPool);
const baseJwtPayload = getBaseJwtPayload({
issuer: issuerUrl,
subject: userData.uuid
subject: userData.uuid,
authTimeInEpoch: jwtConfig.authTimeInEpoch,
minutesToExpiry: jwtConfig.minutesToExpiry
});

const accessToken = getAccessToken(asymmetricKeys, {
Expand Down
6 changes: 6 additions & 0 deletions src/types/awsServices/cognito/cognito.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ interface UserPool {
region?: string;
}

interface JwtConfig {
authTimeInEpoch?: number;
minutesToExpiry?: number;
}

interface GetCognitoTokensProps {
asymmetricKeys: AsymmetricKeys;
user: User;
cognito?: Cognito;
userPool?: UserPool;
jwtConfig?: JwtConfig;
}

interface CognitoTokens {
Expand Down
2 changes: 2 additions & 0 deletions src/types/utils/getBaseJwtPayload.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
interface GetBaseJwtPayloadProps {
issuer: string;
subject: string;
authTimeInEpoch?: number;
minutesToExpiry?: number;
}

interface BaseJwtPayload {
Expand Down
19 changes: 14 additions & 5 deletions src/utils/getBaseJwtPayload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,28 @@ import {

const getBaseJwtPayload = ({
issuer,
subject
subject,
authTimeInEpoch,
minutesToExpiry = 60
}: GetBaseJwtPayloadProps): BaseJwtPayload => {
const currentEpochTime = Math.floor(Date.now() / 1000);
const isEpochValid =
authTimeInEpoch && new Date(authTimeInEpoch * 1000).getTime() > 0;

const authTime = isEpochValid
? authTimeInEpoch
: Math.floor(Date.now() / 1000);

const secondsToExpiry = minutesToExpiry * 60;

return {
sub: subject,
iss: issuer,
origin_jti: getUUID(),
event_id: getUUID(),
jti: getUUID(),
auth_time: currentEpochTime,
exp: currentEpochTime + 60 * 60,
iat: currentEpochTime
auth_time: authTime,
exp: authTime + secondsToExpiry,
iat: authTime
};
};

Expand Down
74 changes: 74 additions & 0 deletions tests/unit/awsServices/cognito/cognito.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,78 @@ describe("Cognito", () => {
expect(error).not.toBeNull();
}
});

it("should return a valid tokens with custom jwt config - expiry", () => {
const asymmetricKeys = utils.getAsymmetricKeys();

const minutesToExpiry = 1;

const { id_token: idToken, access_token: accessToken } =
awsServices.cognito.getCognitoTokens({
asymmetricKeys,
user: {
emailId
},
jwtConfig: {
minutesToExpiry
}
});

let decodedToken: string | jwt.JwtPayload | null = null;
let authTime = 0;
let expiry = 0;
try {
decodedToken = jwt.decode(idToken) as jwt.JwtPayload;
} catch (error) {
expect(error).toBeNull();
}
expect(decodedToken).not.toBeNull();
authTime = decodedToken?.iat || 0;
expiry = decodedToken?.exp || 0;
expect(expiry - authTime).toBe(minutesToExpiry * 60);

try {
decodedToken = jwt.decode(accessToken) as jwt.JwtPayload;
} catch (error) {
expect(error).toBeNull();
}
expect(decodedToken).not.toBeNull();
authTime = decodedToken?.iat || 0;
expiry = decodedToken?.exp || 0;
expect(expiry - authTime).toBe(minutesToExpiry * 60);
});

it("should return a valid tokens with custom jwt config - auth time", () => {
const asymmetricKeys = utils.getAsymmetricKeys();

const authTimeInEpoch = 1000;

const { id_token: idToken, access_token: accessToken } =
awsServices.cognito.getCognitoTokens({
asymmetricKeys,
user: {
emailId
},
jwtConfig: {
authTimeInEpoch
}
});

let decodedToken: string | jwt.JwtPayload | null = null;
try {
decodedToken = jwt.decode(idToken) as jwt.JwtPayload;
} catch (error) {
expect(error).toBeNull();
}
expect(decodedToken).not.toBeNull();
expect(decodedToken?.iat).toBe(authTimeInEpoch);

try {
decodedToken = jwt.decode(accessToken) as jwt.JwtPayload;
} catch (error) {
expect(error).toBeNull();
}
expect(decodedToken).not.toBeNull();
expect(decodedToken?.iat).toBe(authTimeInEpoch);
});
});

0 comments on commit 08254f3

Please # to comment.