Skip to content

Commit 438e344

Browse files
committed
Throw TokenInvalidError for invalid tokens
Wrap the jose errors
1 parent b528dd5 commit 438e344

File tree

3 files changed

+63
-16
lines changed

3 files changed

+63
-16
lines changed

.changeset/rude-snails-tease.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@labdigital/federated-token": minor
3+
---
4+
5+
Throw TokenInvalidError for invalid tokens

src/sign.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,22 @@ describe("Strings", async () => {
7979
iss: "exampleIssuer",
8080
});
8181
});
82+
83+
test("JWT Decrypt with invalid ISS", async () => {
84+
const payload = {
85+
foo: "bar",
86+
};
87+
const invalidSigner = new TokenSigner({
88+
...signOptions,
89+
issuer: "invalidIssuer",
90+
});
91+
92+
const exp = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 90;
93+
const token = await invalidSigner.encryptJWT(payload, exp);
94+
expect(token).toBeDefined();
95+
96+
expect(() => signer.decryptJWT(token)).rejects.toThrowError(
97+
`unexpected "iss" claim value`
98+
);
99+
});
82100
});

src/sign.ts

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import * as jose from "jose";
2-
import { PublicFederatedToken } from "jwt";
2+
import {
3+
PublicFederatedToken,
4+
TokenExpiredError,
5+
TokenInvalidError,
6+
} from "./jwt";
37
import { KeyObject } from "node:crypto";
48

59
type TokenSignerOptions = {
@@ -70,15 +74,28 @@ export class TokenSigner {
7074
}
7175

7276
async verifyJWT(value: string) {
73-
return await jose.jwtVerify(
74-
value,
75-
this._signKeys.getKeyFunction.bind(this._signKeys),
76-
{
77-
algorithms: ["HS256"],
78-
audience: this.config.audience,
79-
issuer: this.config.issuer,
77+
try {
78+
return await jose.jwtVerify(
79+
value,
80+
this._signKeys.getKeyFunction.bind(this._signKeys),
81+
{
82+
algorithms: ["HS256"],
83+
audience: this.config.audience,
84+
issuer: this.config.issuer,
85+
}
86+
);
87+
} catch (e) {
88+
if (e instanceof jose.errors.JWTClaimValidationFailed) {
89+
throw new TokenExpiredError(e.message);
8090
}
81-
);
91+
if (e instanceof jose.errors.JWTExpired) {
92+
throw new TokenExpiredError(e.message);
93+
}
94+
if (e instanceof Error) {
95+
throw new TokenInvalidError(e.message);
96+
}
97+
throw e;
98+
}
8299
}
83100

84101
// For refresh token, encrypt the token (JWE)
@@ -96,14 +113,21 @@ export class TokenSigner {
96113
}
97114

98115
async decryptJWT(jwt: string) {
99-
return await jose.jwtDecrypt(
100-
jwt,
101-
this._encryptKeys.getKeyFunction.bind(this._encryptKeys),
102-
{
103-
audience: this.config.audience,
104-
issuer: this.config.issuer,
116+
try {
117+
return await jose.jwtDecrypt(
118+
jwt,
119+
this._encryptKeys.getKeyFunction.bind(this._encryptKeys),
120+
{
121+
audience: this.config.audience,
122+
issuer: this.config.issuer,
123+
}
124+
);
125+
} catch (e) {
126+
if (e instanceof jose.errors.JWTClaimValidationFailed) {
127+
throw new TokenExpiredError(e.message);
105128
}
106-
);
129+
throw new TokenInvalidError();
130+
}
107131
}
108132
}
109133

0 commit comments

Comments
 (0)