Skip to content

Commit 07c2edc

Browse files
committed
Add ability to set subject
1 parent 1d2b7b3 commit 07c2edc

File tree

6 files changed

+71
-24
lines changed

6 files changed

+71
-24
lines changed

src/gateway.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ describe("GatewayAuthPlugin", () => {
5151
context.federatedToken.setAccessToken("foo", {
5252
token: "bar",
5353
exp: Date.now() + 1000,
54+
sub: "my-user-id",
5455
});
5556
context.federatedToken.setRefreshToken("foo", "bar");
5657
}
@@ -65,6 +66,7 @@ describe("GatewayAuthPlugin", () => {
6566
context.federatedToken?.setAccessToken("foo", {
6667
token: "bar",
6768
exp: Date.now() + 1000,
69+
sub: "my-user-id",
6870
});
6971
return JSON.stringify(context.federatedToken);
7072
},

src/jwt.test.ts

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ describe("PublicFederatedToken", async () => {
3030
exampleName: {
3131
token: "exampleToken",
3232
exp: expireAt,
33+
sub: "exampleSubject",
3334
},
3435
};
3536
token.values = {
@@ -48,17 +49,45 @@ describe("PublicFederatedToken", async () => {
4849
expect(newToken.values).toStrictEqual(token.values);
4950
});
5051

51-
test("loadAccessJWT", async () => {
52+
test("createAccessJWT with TokenSigner create hook", async () => {
53+
const signer = new TokenSigner({
54+
...signOptions,
55+
getSubject: async (token) => token.tokens.exampleName?.sub,
56+
});
57+
5258
const token = new PublicFederatedToken();
53-
const exampleJWT = await signer.signJWT(
54-
{
55-
exp: Date.now() + 1000,
56-
jwe: await signer.encryptObject(token.tokens),
57-
value1: "exampleValue1",
58-
value2: "exampleValue2",
59+
const expireAt = Date.now() + 60;
60+
token.tokens = {
61+
exampleName: {
62+
token: "exampleToken",
63+
exp: expireAt,
64+
sub: "exampleSubject",
5965
},
60-
Date.now() + 1000
61-
);
66+
};
67+
token.values = {
68+
value1: "exampleValue1",
69+
value2: "exampleValue2",
70+
};
71+
72+
const { accessToken, fingerprint } = await token.createAccessJWT(signer);
73+
74+
expect(fingerprint).lengthOf(32);
75+
76+
const newToken = new PublicFederatedToken();
77+
await newToken.loadAccessJWT(signer, accessToken, fingerprint);
78+
expect(newToken.tokens).toStrictEqual(token.tokens);
79+
expect(newToken.refreshTokens).toStrictEqual(token.refreshTokens);
80+
expect(newToken.values).toStrictEqual(token.values);
81+
});
82+
83+
test("loadAccessJWT", async () => {
84+
const token = new PublicFederatedToken();
85+
const exampleJWT = await signer.signJWT({
86+
exp: Date.now() + 1000,
87+
jwe: await signer.encryptObject(token.tokens),
88+
value1: "exampleValue1",
89+
value2: "exampleValue2",
90+
});
6291

6392
await token.loadAccessJWT(signer, exampleJWT);
6493

@@ -75,16 +104,13 @@ describe("PublicFederatedToken", async () => {
75104
test("loadAccessJWT with Fingerprint", async () => {
76105
const token = new PublicFederatedToken();
77106
const fingerprint = generateFingerprint();
78-
const exampleJWT = await signer.signJWT(
79-
{
80-
exp: Date.now() + 1000,
81-
jwe: await signer.encryptObject(token.tokens),
82-
value1: "exampleValue1",
83-
value2: "exampleValue2",
84-
_fingerprint: hashFingerprint(fingerprint),
85-
},
86-
Date.now() + 1000
87-
);
107+
const exampleJWT = await signer.signJWT({
108+
exp: Date.now() + 1000,
109+
jwe: await signer.encryptObject(token.tokens),
110+
value1: "exampleValue1",
111+
value2: "exampleValue2",
112+
_fingerprint: hashFingerprint(fingerprint),
113+
});
88114

89115
expect(fingerprint).lengthOf(32);
90116
await token.loadAccessJWT(signer, exampleJWT, fingerprint);

src/sign.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ describe("Strings", async () => {
4040
});
4141

4242
test("JWT Sign and verify", async () => {
43+
const exp = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 90;
4344
const payload = {
4445
foo: "bar",
46+
exp: exp,
4547
};
4648

47-
const exp = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 90;
48-
const token = await signer.signJWT(payload, exp);
49+
const token = await signer.signJWT(payload);
4950
expect(token).toBeDefined();
5051

5152
const result = await signer.verifyJWT(token);

src/sign.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import * as jose from "jose";
2+
import { PublicFederatedToken } from "jwt";
23
import { KeyObject } from "node:crypto";
34

5+
46
type TokenSignerOptions = {
57
encryptKeys: KeyManagerInterface;
68
signKeys: KeyManagerInterface;
79
audience: string;
810
issuer: string;
11+
getSubject?: (token: PublicFederatedToken) => Promise<string>;
912
};
1013

1114
export class ConfigurationError extends Error {}
@@ -52,10 +55,14 @@ export class TokenSigner {
5255
return JSON.parse(data);
5356
}
5457

55-
async signJWT(payload: any, exp: number) {
58+
async getSubject(token: PublicFederatedToken): Promise<string | undefined> {
59+
return this.config.getSubject ? this.config.getSubject(token) : undefined
60+
}
61+
62+
async signJWT(payload: jose.JWTPayload) {
5663
const { id, key } = await this._signKeys.getActiveKey();
57-
return await new jose.SignJWT(payload)
58-
.setExpirationTime(exp)
64+
65+
return new jose.SignJWT(payload)
5966
.setIssuedAt()
6067
.setProtectedHeader({ alg: "HS256", kid: id })
6168
.setAudience(this.config.audience)

src/token.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ describe("FederatedToken", () => {
77
const token: AccessToken = {
88
token: "exampleToken",
99
exp: 1234567890,
10+
sub: "exampleSubject",
1011
};
1112
federatedToken.setAccessToken("exampleName", token);
1213
assert.equal(federatedToken.tokens.exampleName, token);
@@ -42,6 +43,7 @@ describe("FederatedToken", () => {
4243
federatedToken.setAccessToken("exampleName", {
4344
token: "exampleToken",
4445
exp: 1234567890,
46+
sub: "exampleSubject",
4547
});
4648
assert.isTrue(federatedToken.isAccessTokenModified());
4749
});
@@ -53,6 +55,7 @@ describe("FederatedToken", () => {
5355
exampleName: {
5456
token: "exampleToken",
5557
exp: 1234567890,
58+
sub: "exampleSubject",
5659
},
5760
},
5861
values: {
@@ -70,6 +73,7 @@ describe("FederatedToken", () => {
7073
{
7174
token: "exampleToken",
7275
exp: 1234567890,
76+
sub: "exampleSubject",
7377
},
7478
"Token object should be loaded correctly"
7579
);
@@ -96,6 +100,7 @@ describe("FederatedToken", () => {
96100
exampleName: {
97101
token: "exampleToken",
98102
exp: 1234567890,
103+
sub: "exampleSubject",
99104
},
100105
},
101106
values: {
@@ -113,6 +118,7 @@ describe("FederatedToken", () => {
113118
{
114119
token: "exampleToken",
115120
exp: 1234567890,
121+
sub: "exampleSubject",
116122
},
117123
"Token object should be loaded correctly"
118124
);
@@ -137,6 +143,7 @@ describe("FederatedToken", () => {
137143
federatedToken.setAccessToken("exampleName", {
138144
token: "exampleToken",
139145
exp: 1234567890,
146+
sub: "exampleSubject",
140147
});
141148
federatedToken.values = {
142149
value1: "exampleValue1",
@@ -149,6 +156,7 @@ describe("FederatedToken", () => {
149156
exampleName: {
150157
token: "exampleToken",
151158
exp: 1234567890,
159+
sub: "exampleSubject",
152160
},
153161
},
154162
values: {

src/token.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ export interface AccessToken {
1313
// Expire at, unixtime
1414
token: string;
1515
exp: number;
16+
17+
// Subject, it is most often used for the user-id.
18+
sub: string;
1619
}
1720

1821
export class FederatedToken {

0 commit comments

Comments
 (0)