Skip to content

Commit

Permalink
Merge pull request #47 from pagopa/PIN-1143-add-audience-claim
Browse files Browse the repository at this point in the history
[#PIN-1143] Added optional and configurable audience JWT claim
  • Loading branch information
iwoak authored Feb 23, 2022
2 parents 5b07ee0 + b1a91f1 commit f7ce147
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 2 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ INCLUDE_SPID_USER_ON_INTROSPECTION=true

TOKEN_EXPIRATION=3600
JWT_TOKEN_ISSUER=SPID
JWT_TOKEN_AUDIENCE=https://localhost
JWT_TOKEN_PRIVATE_KEY=""
JWT_TOKEN_KID=key-id-for-your-jwt-key

Expand Down
3 changes: 2 additions & 1 deletion src/handlers/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export const generateToken = (tokenUser: TokenUser | TokenUserL2) =>
tokenUser,
tokenExpiration,
config.JWT_TOKEN_ISSUER,
config.JWT_TOKEN_KID
config.JWT_TOKEN_KID,
config.JWT_TOKEN_AUDIENCE
).bimap(
() => new Error("Error generating JWT Token"),
_ => ({ tokenUser, tokenStr: _ })
Expand Down
29 changes: 29 additions & 0 deletions src/utils/__tests__/jwt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const tokenUser: TokenUser | TokenUserL2 = {
level: "L1",
};
const tokenTtlSeconds = 3600 as NonNegativeInteger;
const aTokenAudience = "AUDIENCE" as NonEmptyString;
const aTokenIssuer = "ISSUER" as NonEmptyString;
const aKeyid = "AKEYID" as NonEmptyString;
const aTokenLengthBytesWithKeyId = 496;
Expand Down Expand Up @@ -74,6 +75,34 @@ describe("Generate a valid JWT Header", () => {
aTokenLengthBytesWithoutKeyId
);
});


it("should generate it without keyd but with audience", async () => {
const errorOrNewJwtToken = await getUserJwt(
aPrivateRsaKey,
tokenUser,
tokenTtlSeconds,
aTokenIssuer,
undefined,
aTokenAudience
).run();
expect(isRight(errorOrNewJwtToken)).toBeTruthy();

if (isRight(errorOrNewJwtToken)) {
const decodedToken = jwt.decode(
errorOrNewJwtToken.value,
{
complete: true,
}
);

if (!decodedToken) {
fail();
}
expect(decodedToken["payload"].aud).toEqual(aTokenAudience);
}
});

it("should return an error if an error occurs during token generation", async () => {
const errorOrNewJwtToken = await getUserJwt(
"aPanInvalidRsaKey" as NonEmptyString,
Expand Down
1 change: 1 addition & 0 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export const JWTParams = t.union([
JWT_TOKEN_PRIVATE_KEY: NonEmptyString
}),
t.partial({
JWT_TOKEN_AUDIENCE: NonEmptyString,
JWT_TOKEN_KID: NonEmptyString
}),
UserRegistryParams
Expand Down
4 changes: 3 additions & 1 deletion src/utils/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ export const getUserJwt = (
tokenUser: TokenUser | TokenUserL2,
tokenTtlSeconds: NonNegativeInteger,
issuer: NonEmptyString,
keyid?: NonEmptyString
keyid?: NonEmptyString,
audience?: NonEmptyString
): TaskEither<Error, string> =>
taskify<Error, string>(cb =>
jwt.sign(
tokenUser,
privateKey,
withoutUndefinedValues({
algorithm: "RS256",
audience,
expiresIn: `${tokenTtlSeconds} seconds`,
issuer,
jwtid: ulid(),
Expand Down

0 comments on commit f7ce147

Please sign in to comment.