@growth-labs/auth 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/config-store.js +5 -1
- package/dist/config-store.js.map +1 -1
- package/dist/middleware/auth.js +2 -2
- package/dist/middleware/auth.js.map +1 -1
- package/dist/options.d.ts +3 -3
- package/dist/options.js +1 -1
- package/dist/options.js.map +1 -1
- package/dist/routes/logout.js +1 -1
- package/dist/routes/logout.js.map +1 -1
- package/dist/server.js +4 -4
- package/dist/server.js.map +1 -1
- package/dist/utils/client-secret.d.ts +1 -1
- package/dist/utils/client-secret.d.ts.map +1 -1
- package/dist/utils/client-secret.js +12 -3
- package/dist/utils/client-secret.js.map +1 -1
- package/dist/utils/openauth.d.ts.map +1 -1
- package/dist/utils/openauth.js +16 -8
- package/dist/utils/openauth.js.map +1 -1
- package/dist/utils/tokens.d.ts +1 -0
- package/dist/utils/tokens.d.ts.map +1 -1
- package/dist/utils/tokens.js +52 -24
- package/dist/utils/tokens.js.map +1 -1
- package/package.json +2 -2
- package/src/config-store.ts +5 -1
- package/src/middleware/auth.ts +2 -2
- package/src/options.ts +1 -1
- package/src/routes/logout.ts +1 -1
- package/src/server.ts +6 -6
- package/src/utils/client-secret.ts +19 -3
- package/src/utils/openauth.ts +18 -9
- package/src/utils/tokens.ts +67 -28
package/README.md
CHANGED
|
@@ -15,8 +15,8 @@ auth({
|
|
|
15
15
|
issuer: 'https://auth.fedweek.com', // Browser-facing OpenAuth issuer URL
|
|
16
16
|
issuerInternal: 'https://auth-internal.example.com', // Optional back-channel issuer URL
|
|
17
17
|
clientId: 'fedweek-prod', // Optional; defaults to request hostname
|
|
18
|
-
clientSecret: 'AUTH_CLIENT_SECRET', // Worker secret binding name, resolved at request time
|
|
19
|
-
resource: 'https://fedweek.com', // RFC 8707 resource/audience URI
|
|
18
|
+
clientSecret: 'AUTH_CLIENT_SECRET', // Worker secret or Secrets Store binding name, resolved at request time
|
|
19
|
+
resource: 'https://fedweek.com', // Required RFC 8707 resource/JWT audience URI
|
|
20
20
|
cookiePrefix: 'fedweek', // → fedweek_at, fedweek_rt, fedweek_provider cookies
|
|
21
21
|
sessionCookieDomain: '.fedweek.com', // Cross-subdomain sharing (optional)
|
|
22
22
|
gatedPaths: ['/premium/*', '/account/*'], // Glob patterns for protected routes
|
|
@@ -48,9 +48,10 @@ auth({
|
|
|
48
48
|
**Middleware** (runs on every request):
|
|
49
49
|
1. Reads `{cookiePrefix}_at` and `{cookiePrefix}_rt` cookies
|
|
50
50
|
2. Verifies access token JWT against the internal issuer's JWKS (`{issuerInternal ?? issuer}/.well-known/jwks.json`, cached in Worker memory)
|
|
51
|
-
3.
|
|
52
|
-
4.
|
|
53
|
-
5.
|
|
51
|
+
3. Requires the access token `aud` to match `resource`; wrong or missing audiences remain unauthenticated
|
|
52
|
+
4. If expired but refresh token valid → silent refresh, verify the new access token audience, then set new cookies
|
|
53
|
+
5. Populates `context.locals.user` as `User | null`
|
|
54
|
+
6. If path matches `gatedPaths` and `user` is null → redirect to `loginPath`
|
|
54
55
|
|
|
55
56
|
**Routes:**
|
|
56
57
|
- `GET /login` — provider-selection page; `?provider=google|password|email-code` starts auth locally and redirects into the issuer's generic `/authorize` endpoint
|
|
@@ -104,7 +105,8 @@ await client.password.reset.confirm({ token, newPassword })
|
|
|
104
105
|
|
|
105
106
|
`authClient(context)` reads the resolved integration config and Worker
|
|
106
107
|
bindings, posts to `{issuerInternal ?? issuer}/api/v1/auth/*`, resolves
|
|
107
|
-
`clientSecret` binding names at request time,
|
|
108
|
+
`clientSecret` Worker secret or Secrets Store binding names at request time,
|
|
109
|
+
sends `client_secret_basic`
|
|
108
110
|
for confidential clients, and includes `client_id`, `redirect_uri`, PKCE
|
|
109
111
|
`code_challenge`, `state`, and `resource` for authorization-code issuing
|
|
110
112
|
calls. Password reset request calls also include `reset_url_base` from the
|
|
@@ -233,7 +235,7 @@ analytics peer is installed.
|
|
|
233
235
|
- Cookie names: `{cookiePrefix}_at`, `{cookiePrefix}_rt`, `{cookiePrefix}_pkce`, `{cookiePrefix}_state`, `{cookiePrefix}_redirect`, `{cookiePrefix}_provider`, `gl_id`
|
|
234
236
|
- PKCE flow with `code_verifier` / `code_challenge` (S256); `{cookiePrefix}_pkce` is scoped to `callbackPath` for issuer redirect flows and set at both `/` and `callbackPath` for consumer-hosted password/code flows that can either post JSON in-place or hand off to callback
|
|
235
237
|
- `issuer` is browser-facing; optional `issuerInternal` is used for token exchange, silent refresh, JWT verification/JWKS lookup, and revocation. If omitted, `issuerInternal` falls back to `issuer`.
|
|
236
|
-
- Confidential OAuth clients use `client_secret_basic` on token exchange and refresh when `clientSecret` is configured. Prefer a Worker secret binding name such as `AUTH_CLIENT_SECRET`; runtime code resolves that binding before calling the issuer.
|
|
238
|
+
- Confidential OAuth clients use `client_secret_basic` on token exchange and refresh when `clientSecret` is configured. Prefer a Worker secret or Cloudflare Secrets Store binding name such as `AUTH_CLIENT_SECRET`; runtime code resolves that binding before calling the issuer and treats binding read failures as auth failures.
|
|
237
239
|
- RFC 8707 `resource` is sent on authorize, token exchange, and refresh when configured
|
|
238
240
|
- `email-code` is a client-side alias for the issuer's OpenAuth `code` provider
|
|
239
241
|
- CSRF state parameter verified on callback
|
package/dist/config-store.js
CHANGED
|
@@ -34,12 +34,16 @@ function resolveEnvMarkers(base) {
|
|
|
34
34
|
if (typeof issuer !== 'string') {
|
|
35
35
|
throw new Error('@growth-labs/auth: issuer must resolve to a string');
|
|
36
36
|
}
|
|
37
|
+
const resource = resolveEnvMarker(base.resource, env);
|
|
38
|
+
if (typeof resource !== 'string') {
|
|
39
|
+
throw new Error('@growth-labs/auth: resource must resolve to a string');
|
|
40
|
+
}
|
|
37
41
|
return {
|
|
38
42
|
...base,
|
|
39
43
|
issuer,
|
|
40
44
|
issuerInternal: resolveEnvMarker(base.issuerInternal, env),
|
|
41
45
|
clientId: resolveEnvMarker(base.clientId, env),
|
|
42
|
-
resource
|
|
46
|
+
resource,
|
|
43
47
|
};
|
|
44
48
|
}
|
|
45
49
|
function anyMarkerPresent(base) {
|
package/dist/config-store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-store.js","sourceRoot":"","sources":["../src/config-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAErE,IAAI,OAAO,GAA+B,IAAI,CAAA;AAE9C,MAAM,UAAU,UAAU,CAAC,MAA2B;IACrD,OAAO,GAAG,MAAM,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,SAAS;IACxB,MAAM,aAAa,GAClB,UAGA,CAAC,kBAAkB,CAAA;IACpB,MAAM,IAAI,GAAG,aAAa,IAAI,OAAO,CAAA;IACrC,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACd,wGAAwG,CACxG,CAAA;IACF,CAAC;IACD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,iBAAiB,CAAC,IAAyB;IACnD,MAAM,GAAG,GACR,UAGA,CAAC,uBAAuB,CAAA;IACzB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACd,qLAAqL,CACrL,CAAA;QACF,CAAC;QACD,OAAO,IAAI,CAAA;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACtE,CAAC;IACD,
|
|
1
|
+
{"version":3,"file":"config-store.js","sourceRoot":"","sources":["../src/config-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAErE,IAAI,OAAO,GAA+B,IAAI,CAAA;AAE9C,MAAM,UAAU,UAAU,CAAC,MAA2B;IACrD,OAAO,GAAG,MAAM,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,SAAS;IACxB,MAAM,aAAa,GAClB,UAGA,CAAC,kBAAkB,CAAA;IACpB,MAAM,IAAI,GAAG,aAAa,IAAI,OAAO,CAAA;IACrC,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACd,wGAAwG,CACxG,CAAA;IACF,CAAC;IACD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,iBAAiB,CAAC,IAAyB;IACnD,MAAM,GAAG,GACR,UAGA,CAAC,uBAAuB,CAAA;IACzB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACd,qLAAqL,CACrL,CAAA;QACF,CAAC;QACD,OAAO,IAAI,CAAA;IACZ,CAAC;IACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACtE,CAAC;IACD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IACrD,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;IACxE,CAAC;IACD,OAAO;QACN,GAAG,IAAI;QACP,MAAM;QACN,cAAc,EAAE,gBAAgB,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC;QAC1D,QAAQ,EAAE,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC;QAC9C,QAAQ;KACR,CAAA;AACF,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAyB;IAClD,OAAO,CACN,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC;QACxB,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC;QAChC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC1B,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAC1B,CAAA;AACF,CAAC"}
|
package/dist/middleware/auth.js
CHANGED
|
@@ -15,7 +15,7 @@ export async function onRequest(context, next) {
|
|
|
15
15
|
let user = null;
|
|
16
16
|
let refreshed = null;
|
|
17
17
|
if (accessToken) {
|
|
18
|
-
const verified = await verifyAccessToken(issuer, accessToken);
|
|
18
|
+
const verified = await verifyAccessToken(issuer, accessToken, { audience: options.resource });
|
|
19
19
|
if (verified) {
|
|
20
20
|
user = {
|
|
21
21
|
id: verified.sub,
|
|
@@ -30,7 +30,7 @@ export async function onRequest(context, next) {
|
|
|
30
30
|
}
|
|
31
31
|
if (!user && refreshToken) {
|
|
32
32
|
const clientId = options.clientId || context.url.hostname;
|
|
33
|
-
const clientSecret = resolveClientSecret(options.clientSecret);
|
|
33
|
+
const clientSecret = await resolveClientSecret(options.clientSecret);
|
|
34
34
|
refreshed = await refreshTokens(issuer, refreshToken, clientId, clientSecret, options.resource);
|
|
35
35
|
if (refreshed) {
|
|
36
36
|
user = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,sBAAsB,CAAA;AAE7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAErE,MAAM,CAAC,KAAK,UAAU,SAAS,CAC9B,OAAwE,EACxE,IAA6B;IAE7B,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;IAC3B,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAA;IAC7C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAE3B,8BAA8B;IAC9B,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IACpE,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IAErE,6BAA6B;IAC7B,IAAI,IAAI,GAAgB,IAAI,CAAA;IAC5B,IAAI,SAAS,GAA8C,IAAI,CAAA;IAE/D,IAAI,WAAW,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/options.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const authOptionsSchema: z.ZodObject<{
|
|
|
5
5
|
issuerInternal: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
6
6
|
clientId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
7
7
|
clientSecret: z.ZodOptional<z.ZodString>;
|
|
8
|
-
resource: z.
|
|
8
|
+
resource: z.ZodEffects<z.ZodString, string, string>;
|
|
9
9
|
cookiePrefix: z.ZodString;
|
|
10
10
|
sessionCookieDomain: z.ZodOptional<z.ZodString>;
|
|
11
11
|
accessTokenMaxAge: z.ZodDefault<z.ZodNumber>;
|
|
@@ -40,6 +40,7 @@ export declare const authOptionsSchema: z.ZodObject<{
|
|
|
40
40
|
renderers: z.ZodDefault<z.ZodType<AuthRenderers, z.ZodTypeDef, AuthRenderers>>;
|
|
41
41
|
}, "strip", z.ZodTypeAny, {
|
|
42
42
|
issuer: string;
|
|
43
|
+
resource: string;
|
|
43
44
|
cookiePrefix: string;
|
|
44
45
|
accessTokenMaxAge: number;
|
|
45
46
|
refreshTokenMaxAge: number;
|
|
@@ -66,15 +67,14 @@ export declare const authOptionsSchema: z.ZodObject<{
|
|
|
66
67
|
issuerInternal?: string | undefined;
|
|
67
68
|
clientId?: string | undefined;
|
|
68
69
|
clientSecret?: string | undefined;
|
|
69
|
-
resource?: string | undefined;
|
|
70
70
|
sessionCookieDomain?: string | undefined;
|
|
71
71
|
}, {
|
|
72
72
|
issuer: string;
|
|
73
|
+
resource: string;
|
|
73
74
|
cookiePrefix: string;
|
|
74
75
|
issuerInternal?: string | undefined;
|
|
75
76
|
clientId?: string | undefined;
|
|
76
77
|
clientSecret?: string | undefined;
|
|
77
|
-
resource?: string | undefined;
|
|
78
78
|
sessionCookieDomain?: string | undefined;
|
|
79
79
|
accessTokenMaxAge?: number | undefined;
|
|
80
80
|
refreshTokenMaxAge?: number | undefined;
|
package/dist/options.js
CHANGED
|
@@ -23,7 +23,7 @@ export const authOptionsSchema = z.object({
|
|
|
23
23
|
// ─── Client identity ───
|
|
24
24
|
clientId: stringOrEnvMarker.optional(),
|
|
25
25
|
clientSecret: z.string().optional(),
|
|
26
|
-
resource: urlOrEnvMarker
|
|
26
|
+
resource: urlOrEnvMarker,
|
|
27
27
|
// ─── Cookie configuration ───
|
|
28
28
|
cookiePrefix: z.string(),
|
|
29
29
|
sessionCookieDomain: z.string().optional(),
|
package/dist/options.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,2EAA2E;AAC3E,oEAAoE;AACpE,uEAAuE;AACvE,uEAAuE;AACvE,MAAM,cAAc,GAAG,CAAC;KACtB,MAAM,EAAE;KACR,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;IACjF,OAAO,EAAE,0DAA0D;CACnE,CAAC,CAAA;AAEH,qEAAqE;AACrE,oEAAoE;AACpE,wEAAwE;AACxE,wEAAwE;AACxE,wDAAwD;AACxD,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;IACzF,OAAO,EAAE,uEAAuE;CAChF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,sBAAsB;IACtB,MAAM,EAAE,cAAc;IACtB,cAAc,EAAE,cAAc,CAAC,QAAQ,EAAE;IAEzC,0BAA0B;IAC1B,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACtC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,QAAQ,EAAE,cAAc
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/logout.js
CHANGED
|
@@ -11,7 +11,7 @@ export async function GET(context) {
|
|
|
11
11
|
const waitUntil = resolveWaitUntil(context);
|
|
12
12
|
// Revoke at issuer (non-blocking)
|
|
13
13
|
if (refreshToken) {
|
|
14
|
-
const clientSecret = resolveClientSecret(options.clientSecret);
|
|
14
|
+
const clientSecret = await resolveClientSecret(options.clientSecret);
|
|
15
15
|
const promise = clientSecret
|
|
16
16
|
? revokeToken(refreshToken, clientId, clientSecret)
|
|
17
17
|
: revokeToken(refreshToken, clientId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,GACT,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAYzD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAsB;IAC/C,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;IAC3B,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;IACzD,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAE3C,kCAAkC;IAClC,IAAI,YAAY,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EACN,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,GACT,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAYzD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAsB;IAC/C,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;IAC3B,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;IACzD,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAE3C,kCAAkC;IAClC,IAAI,YAAY,EAAE,CAAC;QAClB,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;QACpE,MAAM,OAAO,GAAG,YAAY;YAC3B,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC;YACnD,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;QACtC,SAAS,CAAC,OAAO,CAAC,CAAA;IACnB,CAAC;IAED,+EAA+E;IAC/E,yEAAyE;IACzE,iEAAiE;IACjE,IAAI,kBAAkB,CAAC,OAA+C,CAAC,EAAE,CAAC;QACzE,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE;YACrD,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;SACxC,CAAC,CAAA;QACF,SAAS,CAAC,OAAO,CAAC,CAAA;IACnB,CAAC;IAED,0BAA0B;IAC1B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;IAClF,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IAEpD,oCAAoC;IACpC,MAAM,eAAe,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QACnD,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,OAAO,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;KACtC,CAAC,CAAA;IAEF,iBAAiB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAC3C,mBAAmB,CAAC,eAAe,CAAC,CAAA;IACpC,oBAAoB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAE9C,OAAO,eAAe,CAAA;AACvB,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -21,12 +21,12 @@ async function authFlowPayload(options, context) {
|
|
|
21
21
|
code_challenge: await createPKCEChallenge(verifier),
|
|
22
22
|
code_challenge_method: 'S256',
|
|
23
23
|
state,
|
|
24
|
-
|
|
24
|
+
resource: options.resource,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
-
function headersFor(options, context) {
|
|
27
|
+
async function headersFor(options, context) {
|
|
28
28
|
const headers = { 'Content-Type': 'application/json' };
|
|
29
|
-
const secret = resolveClientSecret(options.clientSecret);
|
|
29
|
+
const secret = await resolveClientSecret(options.clientSecret);
|
|
30
30
|
if (secret) {
|
|
31
31
|
headers.Authorization = createClientSecretBasicAuthHeader(clientId(options, context), secret);
|
|
32
32
|
}
|
|
@@ -48,7 +48,7 @@ async function postJson(options, context, pathname, body) {
|
|
|
48
48
|
try {
|
|
49
49
|
const response = await fetch(`${resolveInternalIssuer(options)}${pathname}`, {
|
|
50
50
|
method: 'POST',
|
|
51
|
-
headers: headersFor(options, context),
|
|
51
|
+
headers: await headersFor(options, context),
|
|
52
52
|
body: JSON.stringify(body),
|
|
53
53
|
});
|
|
54
54
|
const json = await readJson(response);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAE7C,OAAO,EAAE,iCAAiC,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACjG,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAiCrD,SAAS,QAAQ,CAAC,OAA4B,EAAE,OAA0B;IACzE,OAAO,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;AAChD,CAAC;AAED,SAAS,WAAW,CAAC,OAA4B,EAAE,OAA0B;IAC5E,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;AACpE,CAAC;AAED,KAAK,UAAU,eAAe,CAC7B,OAA4B,EAC5B,OAA0B;IAE1B,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,OAAO,CAAC,CAAA;IAC3E,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,QAAQ,CAAC,CAAA;IACzE,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAA;IACtC,CAAC;IAED,OAAO;QACN,SAAS,EAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;QACrC,YAAY,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC;QAC3C,cAAc,EAAE,MAAM,mBAAmB,CAAC,QAAQ,CAAC;QACnD,qBAAqB,EAAE,MAAM;QAC7B,KAAK;QACL,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare function resolveClientSecret(clientSecret?: string): string | undefined
|
|
1
|
+
export declare function resolveClientSecret(clientSecret?: string): Promise<string | undefined>;
|
|
2
2
|
export declare function createClientSecretBasicAuthHeader(clientId: string, clientSecret: string): string;
|
|
3
3
|
//# sourceMappingURL=client-secret.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-secret.d.ts","sourceRoot":"","sources":["../../src/utils/client-secret.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-secret.d.ts","sourceRoot":"","sources":["../../src/utils/client-secret.ts"],"names":[],"mappings":"AAMA,wBAAsB,mBAAmB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAa5F;AAED,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAEhG"}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { getRuntimeEnv } from '../runtime.js';
|
|
2
|
-
export function resolveClientSecret(clientSecret) {
|
|
2
|
+
export async function resolveClientSecret(clientSecret) {
|
|
3
3
|
if (!clientSecret)
|
|
4
4
|
return undefined;
|
|
5
5
|
const runtimeValue = getRuntimeEnv()[clientSecret];
|
|
6
|
-
if (typeof runtimeValue === 'string'
|
|
7
|
-
return runtimeValue;
|
|
6
|
+
if (typeof runtimeValue === 'string') {
|
|
7
|
+
return runtimeValue.length > 0 ? runtimeValue : undefined;
|
|
8
|
+
}
|
|
9
|
+
if (isSecretsStoreBinding(runtimeValue)) {
|
|
10
|
+
const resolved = await runtimeValue.get();
|
|
11
|
+
return resolved.length > 0 ? resolved : undefined;
|
|
8
12
|
}
|
|
9
13
|
return clientSecret;
|
|
10
14
|
}
|
|
@@ -15,4 +19,9 @@ function formEncode(value) {
|
|
|
15
19
|
const params = new URLSearchParams({ value });
|
|
16
20
|
return params.toString().slice('value='.length);
|
|
17
21
|
}
|
|
22
|
+
function isSecretsStoreBinding(value) {
|
|
23
|
+
return (typeof value === 'object' &&
|
|
24
|
+
value !== null &&
|
|
25
|
+
typeof value.get === 'function');
|
|
26
|
+
}
|
|
18
27
|
//# sourceMappingURL=client-secret.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-secret.js","sourceRoot":"","sources":["../../src/utils/client-secret.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"client-secret.js","sourceRoot":"","sources":["../../src/utils/client-secret.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAM7C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,YAAqB;IAC9D,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAA;IAEnC,MAAM,YAAY,GAAG,aAAa,EAAE,CAAC,YAAY,CAAC,CAAA;IAClD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1D,CAAC;IACD,IAAI,qBAAqB,CAAC,YAAY,CAAC,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,CAAA;QACzC,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAClD,CAAC;IAED,OAAO,YAAY,CAAA;AACpB,CAAC;AAED,MAAM,UAAU,iCAAiC,CAAC,QAAgB,EAAE,YAAoB;IACvF,OAAO,SAAS,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,CAAA;AAC9E,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAChC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IAC7C,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;AAChD,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc;IAC5C,OAAO,CACN,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAQ,KAA2B,CAAC,GAAG,KAAK,UAAU,CACtD,CAAA;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openauth.d.ts","sourceRoot":"","sources":["../../src/utils/openauth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAOtD,MAAM,WAAW,QAAQ;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACnB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAY7E;AAED,wBAAsB,mBAAmB,CACxC,OAAO,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,EACrB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB/D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAGlE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAG9D;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAG7C;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAG5C;
|
|
1
|
+
{"version":3,"file":"openauth.d.ts","sourceRoot":"","sources":["../../src/utils/openauth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAOtD,MAAM,WAAW,QAAQ;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACnB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAY7E;AAED,wBAAsB,mBAAmB,CACxC,OAAO,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,EACrB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB/D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAGlE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAG9D;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAG7C;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAG5C;AAYD,wBAAsB,YAAY,CACjC,WAAW,EAAE,GAAG,EAChB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,kBAAkB,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAClD,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAmDrC;AAED,wBAAsB,WAAW,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAqBf"}
|
package/dist/utils/openauth.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createClientSecretBasicAuthHeader, resolveClientSecret } from './client
|
|
|
3
3
|
import { resolveInternalIssuer } from './issuer.js';
|
|
4
4
|
import { generatePKCE } from './pkce.js';
|
|
5
5
|
import { generateState } from './state.js';
|
|
6
|
-
import {
|
|
6
|
+
import { verifyIssuedAccessTokenClaims } from './tokens.js';
|
|
7
7
|
export async function createAuthFlow(context) {
|
|
8
8
|
const options = getConfig();
|
|
9
9
|
const { verifier, challenge } = await generatePKCE();
|
|
@@ -28,9 +28,8 @@ export async function getAuthorizationUrl(context, provider, _redirectPath, auth
|
|
|
28
28
|
code_challenge: flow.challenge,
|
|
29
29
|
code_challenge_method: 'S256',
|
|
30
30
|
provider,
|
|
31
|
+
resource: options.resource,
|
|
31
32
|
});
|
|
32
|
-
if (options.resource)
|
|
33
|
-
params.set('resource', options.resource);
|
|
34
33
|
return {
|
|
35
34
|
url: `${options.issuer}/authorize?${params}`,
|
|
36
35
|
pkceVerifier: flow.verifier,
|
|
@@ -53,12 +52,18 @@ export function getResetPasswordUrl() {
|
|
|
53
52
|
const options = getConfig();
|
|
54
53
|
return `${options.issuer}/reset-password`;
|
|
55
54
|
}
|
|
55
|
+
function tokenResponseHasTokens(data) {
|
|
56
|
+
if (typeof data !== 'object' || data === null)
|
|
57
|
+
return false;
|
|
58
|
+
return (typeof data.access_token === 'string' &&
|
|
59
|
+
typeof data.refresh_token === 'string');
|
|
60
|
+
}
|
|
56
61
|
export async function exchangeCode(callbackUrl, code, codeVerifier, providerFromCookie) {
|
|
57
62
|
const options = getConfig();
|
|
58
63
|
const issuer = resolveInternalIssuer(options);
|
|
59
64
|
const clientId = options.clientId || callbackUrl.hostname;
|
|
60
65
|
const redirectUri = new URL(options.callbackPath, callbackUrl.origin).toString();
|
|
61
|
-
const clientSecret = resolveClientSecret(options.clientSecret);
|
|
66
|
+
const clientSecret = await resolveClientSecret(options.clientSecret);
|
|
62
67
|
const headers = {
|
|
63
68
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
64
69
|
};
|
|
@@ -71,9 +76,8 @@ export async function exchangeCode(callbackUrl, code, codeVerifier, providerFrom
|
|
|
71
76
|
code_verifier: codeVerifier,
|
|
72
77
|
redirect_uri: redirectUri,
|
|
73
78
|
client_id: clientId,
|
|
79
|
+
resource: options.resource,
|
|
74
80
|
});
|
|
75
|
-
if (options.resource)
|
|
76
|
-
body.set('resource', options.resource);
|
|
77
81
|
try {
|
|
78
82
|
const response = await fetch(`${issuer}/token`, {
|
|
79
83
|
method: 'POST',
|
|
@@ -82,8 +86,12 @@ export async function exchangeCode(callbackUrl, code, codeVerifier, providerFrom
|
|
|
82
86
|
});
|
|
83
87
|
if (!response.ok)
|
|
84
88
|
return null;
|
|
85
|
-
const data =
|
|
86
|
-
|
|
89
|
+
const data = await response.json();
|
|
90
|
+
if (!tokenResponseHasTokens(data))
|
|
91
|
+
return null;
|
|
92
|
+
const claims = await verifyIssuedAccessTokenClaims(issuer, data.access_token, options.resource);
|
|
93
|
+
if (!claims)
|
|
94
|
+
return null;
|
|
87
95
|
return {
|
|
88
96
|
accessToken: data.access_token,
|
|
89
97
|
refreshToken: data.refresh_token,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openauth.js","sourceRoot":"","sources":["../../src/utils/openauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C,OAAO,EAAE,iCAAiC,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC3F,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"openauth.js","sourceRoot":"","sources":["../../src/utils/openauth.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/tokens.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export interface VerifyAccessTokenOptions {
|
|
|
18
18
|
algorithms?: string[];
|
|
19
19
|
}
|
|
20
20
|
export declare function verifyAccessToken(issuer: string, token: string, options?: VerifyAccessTokenOptions): Promise<VerifiedClaims | null>;
|
|
21
|
+
export declare function verifyIssuedAccessTokenClaims(issuer: string, token: string, audience: string | undefined): Promise<TokenPayloadClaims | null>;
|
|
21
22
|
export declare function refreshTokens(issuer: string, refreshToken: string, clientId?: string, clientSecret?: string, resource?: string): Promise<TokenRefreshResult | null>;
|
|
22
23
|
export declare function decodeJwtPayload(jwt: string): Record<string, unknown>;
|
|
23
24
|
/** @internal Test-only helper. Not exported from @growth-labs/auth/utils. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AA8DrD,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACzD,SAAS,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAWvF;AAYD,MAAM,WAAW,wBAAwB;IACxC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B,iGAAiG;IACjG,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AA8DrD,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACzD,SAAS,EAAE,OAAO,CAAA;CAClB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAWvF;AAYD,MAAM,WAAW,wBAAwB;IACxC,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAC5B,iGAAiG;IACjG,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AA4BD,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,wBAA6B,GACpC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAYhC;AAED,wBAAsB,6BAA6B,CAClD,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAKpC;AA6BD,wBAAsB,aAAa,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErE;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
package/dist/utils/tokens.js
CHANGED
|
@@ -66,7 +66,7 @@ function isExpiredJwtError(err) {
|
|
|
66
66
|
'code' in err &&
|
|
67
67
|
err.code === 'ERR_JWT_EXPIRED'));
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
async function verifyAccessTokenPayload(issuer, token, options = {}) {
|
|
70
70
|
try {
|
|
71
71
|
const header = decodeJwtHeader(token);
|
|
72
72
|
const kid = typeof header.kid === 'string' ? header.kid : undefined;
|
|
@@ -79,15 +79,7 @@ export async function verifyAccessToken(issuer, token, options = {}) {
|
|
|
79
79
|
if (payload.mode !== 'access') {
|
|
80
80
|
throw new Error(`unexpected token mode: ${String(payload.mode)}`);
|
|
81
81
|
}
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
sub: claims.sub,
|
|
85
|
-
email: claims.email,
|
|
86
|
-
name: claims.name,
|
|
87
|
-
image: claims.image,
|
|
88
|
-
synthetic: payload.synthetic === true ? true : undefined,
|
|
89
|
-
purpose: typeof payload.purpose === 'string' ? payload.purpose : undefined,
|
|
90
|
-
};
|
|
82
|
+
return payload;
|
|
91
83
|
}
|
|
92
84
|
catch (err) {
|
|
93
85
|
if (!isExpiredJwtError(err)) {
|
|
@@ -96,7 +88,49 @@ export async function verifyAccessToken(issuer, token, options = {}) {
|
|
|
96
88
|
return null;
|
|
97
89
|
}
|
|
98
90
|
}
|
|
91
|
+
export async function verifyAccessToken(issuer, token, options = {}) {
|
|
92
|
+
const payload = await verifyAccessTokenPayload(issuer, token, options);
|
|
93
|
+
if (!payload)
|
|
94
|
+
return null;
|
|
95
|
+
const claims = extractTokenClaims(payload);
|
|
96
|
+
return {
|
|
97
|
+
sub: claims.sub,
|
|
98
|
+
email: claims.email,
|
|
99
|
+
name: claims.name,
|
|
100
|
+
image: claims.image,
|
|
101
|
+
synthetic: payload.synthetic === true ? true : undefined,
|
|
102
|
+
purpose: typeof payload.purpose === 'string' ? payload.purpose : undefined,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export async function verifyIssuedAccessTokenClaims(issuer, token, audience) {
|
|
106
|
+
if (!audience)
|
|
107
|
+
return null;
|
|
108
|
+
const payload = await verifyAccessTokenPayload(issuer, token, { audience });
|
|
109
|
+
if (!payload)
|
|
110
|
+
return null;
|
|
111
|
+
return extractTokenClaims(payload);
|
|
112
|
+
}
|
|
113
|
+
function tokenResponseHasTokens(data) {
|
|
114
|
+
if (typeof data !== 'object' || data === null)
|
|
115
|
+
return false;
|
|
116
|
+
return (typeof data.access_token === 'string' &&
|
|
117
|
+
typeof data.refresh_token === 'string');
|
|
118
|
+
}
|
|
119
|
+
function tokenResultFromClaims(accessToken, refreshToken, claims) {
|
|
120
|
+
return {
|
|
121
|
+
accessToken,
|
|
122
|
+
refreshToken,
|
|
123
|
+
claims: {
|
|
124
|
+
sub: claims.sub,
|
|
125
|
+
email: claims.email,
|
|
126
|
+
name: claims.name,
|
|
127
|
+
image: claims.image,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
99
131
|
export async function refreshTokens(issuer, refreshToken, clientId, clientSecret, resource) {
|
|
132
|
+
if (!resource)
|
|
133
|
+
return null;
|
|
100
134
|
try {
|
|
101
135
|
const params = new URLSearchParams({
|
|
102
136
|
grant_type: 'refresh_token',
|
|
@@ -104,8 +138,7 @@ export async function refreshTokens(issuer, refreshToken, clientId, clientSecret
|
|
|
104
138
|
});
|
|
105
139
|
if (clientId)
|
|
106
140
|
params.set('client_id', clientId);
|
|
107
|
-
|
|
108
|
-
params.set('resource', resource);
|
|
141
|
+
params.set('resource', resource);
|
|
109
142
|
const headers = {
|
|
110
143
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
111
144
|
};
|
|
@@ -119,18 +152,13 @@ export async function refreshTokens(issuer, refreshToken, clientId, clientSecret
|
|
|
119
152
|
});
|
|
120
153
|
if (!response.ok)
|
|
121
154
|
return null;
|
|
122
|
-
const data =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
email: claims.email,
|
|
130
|
-
name: claims.name,
|
|
131
|
-
image: claims.image,
|
|
132
|
-
},
|
|
133
|
-
};
|
|
155
|
+
const data = await response.json();
|
|
156
|
+
if (!tokenResponseHasTokens(data))
|
|
157
|
+
return null;
|
|
158
|
+
const claims = await verifyIssuedAccessTokenClaims(issuer, data.access_token, resource);
|
|
159
|
+
if (!claims)
|
|
160
|
+
return null;
|
|
161
|
+
return tokenResultFromClaims(data.access_token, data.refresh_token, claims);
|
|
134
162
|
}
|
|
135
163
|
catch {
|
|
136
164
|
return null;
|
package/dist/utils/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/utils/tokens.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@growth-labs/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"typescript": "^5.8.0",
|
|
58
58
|
"vite": "^7.3.5",
|
|
59
59
|
"vitest": "^4.1.8",
|
|
60
|
-
"@growth-labs/analytics": "0.
|
|
60
|
+
"@growth-labs/analytics": "0.14.6"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsc",
|
package/src/config-store.ts
CHANGED
|
@@ -51,12 +51,16 @@ function resolveEnvMarkers(base: ResolvedAuthOptions): ResolvedAuthOptions {
|
|
|
51
51
|
if (typeof issuer !== 'string') {
|
|
52
52
|
throw new Error('@growth-labs/auth: issuer must resolve to a string')
|
|
53
53
|
}
|
|
54
|
+
const resource = resolveEnvMarker(base.resource, env)
|
|
55
|
+
if (typeof resource !== 'string') {
|
|
56
|
+
throw new Error('@growth-labs/auth: resource must resolve to a string')
|
|
57
|
+
}
|
|
54
58
|
return {
|
|
55
59
|
...base,
|
|
56
60
|
issuer,
|
|
57
61
|
issuerInternal: resolveEnvMarker(base.issuerInternal, env),
|
|
58
62
|
clientId: resolveEnvMarker(base.clientId, env),
|
|
59
|
-
resource
|
|
63
|
+
resource,
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
|
package/src/middleware/auth.ts
CHANGED
|
@@ -23,7 +23,7 @@ export async function onRequest(
|
|
|
23
23
|
let refreshed: Awaited<ReturnType<typeof refreshTokens>> = null
|
|
24
24
|
|
|
25
25
|
if (accessToken) {
|
|
26
|
-
const verified = await verifyAccessToken(issuer, accessToken)
|
|
26
|
+
const verified = await verifyAccessToken(issuer, accessToken, { audience: options.resource })
|
|
27
27
|
if (verified) {
|
|
28
28
|
user = {
|
|
29
29
|
id: verified.sub,
|
|
@@ -39,7 +39,7 @@ export async function onRequest(
|
|
|
39
39
|
|
|
40
40
|
if (!user && refreshToken) {
|
|
41
41
|
const clientId = options.clientId || context.url.hostname
|
|
42
|
-
const clientSecret = resolveClientSecret(options.clientSecret)
|
|
42
|
+
const clientSecret = await resolveClientSecret(options.clientSecret)
|
|
43
43
|
refreshed = await refreshTokens(issuer, refreshToken, clientId, clientSecret, options.resource)
|
|
44
44
|
if (refreshed) {
|
|
45
45
|
user = {
|
package/src/options.ts
CHANGED
|
@@ -28,7 +28,7 @@ export const authOptionsSchema = z.object({
|
|
|
28
28
|
// ─── Client identity ───
|
|
29
29
|
clientId: stringOrEnvMarker.optional(),
|
|
30
30
|
clientSecret: z.string().optional(),
|
|
31
|
-
resource: urlOrEnvMarker
|
|
31
|
+
resource: urlOrEnvMarker,
|
|
32
32
|
|
|
33
33
|
// ─── Cookie configuration ───
|
|
34
34
|
cookiePrefix: z.string(),
|
package/src/routes/logout.ts
CHANGED
|
@@ -28,7 +28,7 @@ export async function GET(context: LogoutContext): Promise<Response> {
|
|
|
28
28
|
|
|
29
29
|
// Revoke at issuer (non-blocking)
|
|
30
30
|
if (refreshToken) {
|
|
31
|
-
const clientSecret = resolveClientSecret(options.clientSecret)
|
|
31
|
+
const clientSecret = await resolveClientSecret(options.clientSecret)
|
|
32
32
|
const promise = clientSecret
|
|
33
33
|
? revokeToken(refreshToken, clientId, clientSecret)
|
|
34
34
|
: revokeToken(refreshToken, clientId)
|
package/src/server.ts
CHANGED
|
@@ -33,7 +33,7 @@ interface AuthFlowPayload {
|
|
|
33
33
|
code_challenge: string
|
|
34
34
|
code_challenge_method: 'S256'
|
|
35
35
|
state: string
|
|
36
|
-
resource
|
|
36
|
+
resource: string
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
function clientId(options: ResolvedAuthOptions, context: AuthClientContext): string {
|
|
@@ -60,16 +60,16 @@ async function authFlowPayload(
|
|
|
60
60
|
code_challenge: await createPKCEChallenge(verifier),
|
|
61
61
|
code_challenge_method: 'S256',
|
|
62
62
|
state,
|
|
63
|
-
|
|
63
|
+
resource: options.resource,
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
function headersFor(
|
|
67
|
+
async function headersFor(
|
|
68
68
|
options: ResolvedAuthOptions,
|
|
69
69
|
context: AuthClientContext,
|
|
70
|
-
): Record<string, string
|
|
70
|
+
): Promise<Record<string, string>> {
|
|
71
71
|
const headers: Record<string, string> = { 'Content-Type': 'application/json' }
|
|
72
|
-
const secret = resolveClientSecret(options.clientSecret)
|
|
72
|
+
const secret = await resolveClientSecret(options.clientSecret)
|
|
73
73
|
if (secret) {
|
|
74
74
|
headers.Authorization = createClientSecretBasicAuthHeader(clientId(options, context), secret)
|
|
75
75
|
}
|
|
@@ -98,7 +98,7 @@ async function postJson<T extends AuthClientCodeResult | AuthClientOkResult>(
|
|
|
98
98
|
try {
|
|
99
99
|
const response = await fetch(`${resolveInternalIssuer(options)}${pathname}`, {
|
|
100
100
|
method: 'POST',
|
|
101
|
-
headers: headersFor(options, context),
|
|
101
|
+
headers: await headersFor(options, context),
|
|
102
102
|
body: JSON.stringify(body),
|
|
103
103
|
})
|
|
104
104
|
const json = await readJson(response)
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { getRuntimeEnv } from '../runtime.js'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
interface SecretsStoreBinding {
|
|
4
|
+
get(): Promise<string>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export async function resolveClientSecret(clientSecret?: string): Promise<string | undefined> {
|
|
4
8
|
if (!clientSecret) return undefined
|
|
5
9
|
|
|
6
10
|
const runtimeValue = getRuntimeEnv()[clientSecret]
|
|
7
|
-
if (typeof runtimeValue === 'string'
|
|
8
|
-
return runtimeValue
|
|
11
|
+
if (typeof runtimeValue === 'string') {
|
|
12
|
+
return runtimeValue.length > 0 ? runtimeValue : undefined
|
|
13
|
+
}
|
|
14
|
+
if (isSecretsStoreBinding(runtimeValue)) {
|
|
15
|
+
const resolved = await runtimeValue.get()
|
|
16
|
+
return resolved.length > 0 ? resolved : undefined
|
|
9
17
|
}
|
|
10
18
|
|
|
11
19
|
return clientSecret
|
|
@@ -19,3 +27,11 @@ function formEncode(value: string): string {
|
|
|
19
27
|
const params = new URLSearchParams({ value })
|
|
20
28
|
return params.toString().slice('value='.length)
|
|
21
29
|
}
|
|
30
|
+
|
|
31
|
+
function isSecretsStoreBinding(value: unknown): value is SecretsStoreBinding {
|
|
32
|
+
return (
|
|
33
|
+
typeof value === 'object' &&
|
|
34
|
+
value !== null &&
|
|
35
|
+
typeof (value as { get?: unknown }).get === 'function'
|
|
36
|
+
)
|
|
37
|
+
}
|
package/src/utils/openauth.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { createClientSecretBasicAuthHeader, resolveClientSecret } from './client
|
|
|
4
4
|
import { resolveInternalIssuer } from './issuer.js'
|
|
5
5
|
import { generatePKCE } from './pkce.js'
|
|
6
6
|
import { generateState } from './state.js'
|
|
7
|
-
import {
|
|
7
|
+
import { verifyIssuedAccessTokenClaims } from './tokens.js'
|
|
8
8
|
|
|
9
9
|
export interface AuthFlow {
|
|
10
10
|
verifier: string
|
|
@@ -46,8 +46,8 @@ export async function getAuthorizationUrl(
|
|
|
46
46
|
code_challenge: flow.challenge,
|
|
47
47
|
code_challenge_method: 'S256',
|
|
48
48
|
provider,
|
|
49
|
+
resource: options.resource,
|
|
49
50
|
})
|
|
50
|
-
if (options.resource) params.set('resource', options.resource)
|
|
51
51
|
|
|
52
52
|
return {
|
|
53
53
|
url: `${options.issuer}/authorize?${params}`,
|
|
@@ -76,6 +76,16 @@ export function getResetPasswordUrl(): string {
|
|
|
76
76
|
return `${options.issuer}/reset-password`
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function tokenResponseHasTokens(
|
|
80
|
+
data: unknown,
|
|
81
|
+
): data is { access_token: string; refresh_token: string } {
|
|
82
|
+
if (typeof data !== 'object' || data === null) return false
|
|
83
|
+
return (
|
|
84
|
+
typeof (data as { access_token?: unknown }).access_token === 'string' &&
|
|
85
|
+
typeof (data as { refresh_token?: unknown }).refresh_token === 'string'
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
79
89
|
export async function exchangeCode(
|
|
80
90
|
callbackUrl: URL,
|
|
81
91
|
code: string,
|
|
@@ -86,7 +96,7 @@ export async function exchangeCode(
|
|
|
86
96
|
const issuer = resolveInternalIssuer(options)
|
|
87
97
|
const clientId = options.clientId || callbackUrl.hostname
|
|
88
98
|
const redirectUri = new URL(options.callbackPath, callbackUrl.origin).toString()
|
|
89
|
-
const clientSecret = resolveClientSecret(options.clientSecret)
|
|
99
|
+
const clientSecret = await resolveClientSecret(options.clientSecret)
|
|
90
100
|
const headers: Record<string, string> = {
|
|
91
101
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
92
102
|
}
|
|
@@ -99,8 +109,8 @@ export async function exchangeCode(
|
|
|
99
109
|
code_verifier: codeVerifier,
|
|
100
110
|
redirect_uri: redirectUri,
|
|
101
111
|
client_id: clientId,
|
|
112
|
+
resource: options.resource,
|
|
102
113
|
})
|
|
103
|
-
if (options.resource) body.set('resource', options.resource)
|
|
104
114
|
|
|
105
115
|
try {
|
|
106
116
|
const response = await fetch(`${issuer}/token`, {
|
|
@@ -111,12 +121,11 @@ export async function exchangeCode(
|
|
|
111
121
|
|
|
112
122
|
if (!response.ok) return null
|
|
113
123
|
|
|
114
|
-
const data =
|
|
115
|
-
|
|
116
|
-
refresh_token: string
|
|
117
|
-
}
|
|
124
|
+
const data = await response.json()
|
|
125
|
+
if (!tokenResponseHasTokens(data)) return null
|
|
118
126
|
|
|
119
|
-
const claims =
|
|
127
|
+
const claims = await verifyIssuedAccessTokenClaims(issuer, data.access_token, options.resource)
|
|
128
|
+
if (!claims) return null
|
|
120
129
|
|
|
121
130
|
return {
|
|
122
131
|
accessToken: data.access_token,
|
package/src/utils/tokens.ts
CHANGED
|
@@ -105,11 +105,11 @@ export interface VerifyAccessTokenOptions {
|
|
|
105
105
|
algorithms?: string[]
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
async function verifyAccessTokenPayload(
|
|
109
109
|
issuer: string,
|
|
110
110
|
token: string,
|
|
111
111
|
options: VerifyAccessTokenOptions = {},
|
|
112
|
-
): Promise<
|
|
112
|
+
): Promise<Record<string, unknown> | null> {
|
|
113
113
|
try {
|
|
114
114
|
const header = decodeJwtHeader(token)
|
|
115
115
|
const kid = typeof header.kid === 'string' ? header.kid : undefined
|
|
@@ -122,15 +122,7 @@ export async function verifyAccessToken(
|
|
|
122
122
|
if (payload.mode !== 'access') {
|
|
123
123
|
throw new Error(`unexpected token mode: ${String(payload.mode)}`)
|
|
124
124
|
}
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
sub: claims.sub,
|
|
128
|
-
email: claims.email,
|
|
129
|
-
name: claims.name,
|
|
130
|
-
image: claims.image,
|
|
131
|
-
synthetic: payload.synthetic === true ? true : undefined,
|
|
132
|
-
purpose: typeof payload.purpose === 'string' ? payload.purpose : undefined,
|
|
133
|
-
}
|
|
125
|
+
return payload as Record<string, unknown>
|
|
134
126
|
} catch (err) {
|
|
135
127
|
if (!isExpiredJwtError(err)) {
|
|
136
128
|
console.error('verifyAccessToken error:', err)
|
|
@@ -139,6 +131,62 @@ export async function verifyAccessToken(
|
|
|
139
131
|
}
|
|
140
132
|
}
|
|
141
133
|
|
|
134
|
+
export async function verifyAccessToken(
|
|
135
|
+
issuer: string,
|
|
136
|
+
token: string,
|
|
137
|
+
options: VerifyAccessTokenOptions = {},
|
|
138
|
+
): Promise<VerifiedClaims | null> {
|
|
139
|
+
const payload = await verifyAccessTokenPayload(issuer, token, options)
|
|
140
|
+
if (!payload) return null
|
|
141
|
+
const claims = extractTokenClaims(payload)
|
|
142
|
+
return {
|
|
143
|
+
sub: claims.sub,
|
|
144
|
+
email: claims.email,
|
|
145
|
+
name: claims.name,
|
|
146
|
+
image: claims.image,
|
|
147
|
+
synthetic: payload.synthetic === true ? true : undefined,
|
|
148
|
+
purpose: typeof payload.purpose === 'string' ? payload.purpose : undefined,
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function verifyIssuedAccessTokenClaims(
|
|
153
|
+
issuer: string,
|
|
154
|
+
token: string,
|
|
155
|
+
audience: string | undefined,
|
|
156
|
+
): Promise<TokenPayloadClaims | null> {
|
|
157
|
+
if (!audience) return null
|
|
158
|
+
const payload = await verifyAccessTokenPayload(issuer, token, { audience })
|
|
159
|
+
if (!payload) return null
|
|
160
|
+
return extractTokenClaims(payload)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function tokenResponseHasTokens(
|
|
164
|
+
data: unknown,
|
|
165
|
+
): data is { access_token: string; refresh_token: string } {
|
|
166
|
+
if (typeof data !== 'object' || data === null) return false
|
|
167
|
+
return (
|
|
168
|
+
typeof (data as { access_token?: unknown }).access_token === 'string' &&
|
|
169
|
+
typeof (data as { refresh_token?: unknown }).refresh_token === 'string'
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function tokenResultFromClaims(
|
|
174
|
+
accessToken: string,
|
|
175
|
+
refreshToken: string,
|
|
176
|
+
claims: TokenPayloadClaims,
|
|
177
|
+
): TokenRefreshResult {
|
|
178
|
+
return {
|
|
179
|
+
accessToken,
|
|
180
|
+
refreshToken,
|
|
181
|
+
claims: {
|
|
182
|
+
sub: claims.sub,
|
|
183
|
+
email: claims.email,
|
|
184
|
+
name: claims.name,
|
|
185
|
+
image: claims.image,
|
|
186
|
+
},
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
142
190
|
export async function refreshTokens(
|
|
143
191
|
issuer: string,
|
|
144
192
|
refreshToken: string,
|
|
@@ -146,13 +194,14 @@ export async function refreshTokens(
|
|
|
146
194
|
clientSecret?: string,
|
|
147
195
|
resource?: string,
|
|
148
196
|
): Promise<TokenRefreshResult | null> {
|
|
197
|
+
if (!resource) return null
|
|
149
198
|
try {
|
|
150
199
|
const params = new URLSearchParams({
|
|
151
200
|
grant_type: 'refresh_token',
|
|
152
201
|
refresh_token: refreshToken,
|
|
153
202
|
})
|
|
154
203
|
if (clientId) params.set('client_id', clientId)
|
|
155
|
-
|
|
204
|
+
params.set('resource', resource)
|
|
156
205
|
|
|
157
206
|
const headers: Record<string, string> = {
|
|
158
207
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
@@ -169,23 +218,13 @@ export async function refreshTokens(
|
|
|
169
218
|
|
|
170
219
|
if (!response.ok) return null
|
|
171
220
|
|
|
172
|
-
const data =
|
|
173
|
-
|
|
174
|
-
refresh_token: string
|
|
175
|
-
}
|
|
221
|
+
const data = await response.json()
|
|
222
|
+
if (!tokenResponseHasTokens(data)) return null
|
|
176
223
|
|
|
177
|
-
const claims =
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
refreshToken: data.refresh_token,
|
|
182
|
-
claims: {
|
|
183
|
-
sub: claims.sub,
|
|
184
|
-
email: claims.email,
|
|
185
|
-
name: claims.name,
|
|
186
|
-
image: claims.image,
|
|
187
|
-
},
|
|
188
|
-
}
|
|
224
|
+
const claims = await verifyIssuedAccessTokenClaims(issuer, data.access_token, resource)
|
|
225
|
+
if (!claims) return null
|
|
226
|
+
|
|
227
|
+
return tokenResultFromClaims(data.access_token, data.refresh_token, claims)
|
|
189
228
|
} catch {
|
|
190
229
|
return null
|
|
191
230
|
}
|