@tdacorp/identity-client 0.2.4 → 0.2.6
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 +20 -0
- package/dist/{chunk-HO6U23GY.js → chunk-36WOXP7V.js} +24 -4
- package/dist/index.cjs +24 -4
- package/dist/index.js +1 -1
- package/dist/next.cjs +29 -5
- package/dist/next.d.cts +36 -5
- package/dist/next.d.ts +36 -5
- package/dist/next.js +7 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -302,6 +302,26 @@ breaking rename (`middleware.ts` → `proxy.ts`) to keep working on Next.js
|
|
|
302
302
|
package ships Route Handlers a consuming app mounts wherever it wants
|
|
303
303
|
instead.
|
|
304
304
|
|
|
305
|
+
Both factories' `redirectUri` accepts a function as well as a plain string —
|
|
306
|
+
`(request) => string`, useful when the app is reachable at more than one
|
|
307
|
+
origin (a preview deployment per branch, say):
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
redirectUri: (request) => `${request.nextUrl.origin}/api/auth/callback`,
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The resolved value must be identical on both the login and callback route's
|
|
314
|
+
own `redirectUri`, since the token endpoint checks it against what the
|
|
315
|
+
authorization request used (RFC 6749 §4.1.3) — true automatically for
|
|
316
|
+
`request.nextUrl.origin`, since one browser session's login and callback
|
|
317
|
+
requests share a domain.
|
|
318
|
+
|
|
319
|
+
`createCallbackRoute` also accepts `clientAuthMethod`, the same option
|
|
320
|
+
`exchangeAuthorizationCode` takes directly (see "Token exchange, refresh,
|
|
321
|
+
and client credentials" above) — set it to `'client_secret_post'` if your
|
|
322
|
+
relying party is registered on the identity platform for that method
|
|
323
|
+
instead of the default `client_secret_basic`.
|
|
324
|
+
|
|
305
325
|
## Limitations in v0.1
|
|
306
326
|
|
|
307
327
|
- **No built-in fallback for an `indeterminate` `permits()` result.** That is
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/discovery.ts
|
|
2
2
|
import { createRemoteJWKSet } from "jose";
|
|
3
3
|
var DISCOVERY_CACHE_TTL_MS = 6e5;
|
|
4
|
+
var FETCH_TIMEOUT_MS = 2500;
|
|
4
5
|
var CACHE_MAX_ENTRIES = 100;
|
|
5
6
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
6
7
|
var discoveryPending = /* @__PURE__ */ new Map();
|
|
@@ -71,7 +72,10 @@ async function fetchDiscovery(issuerUrl) {
|
|
|
71
72
|
}
|
|
72
73
|
const pending = discoveryPending.get(issuerUrl);
|
|
73
74
|
if (pending) return pending;
|
|
74
|
-
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
75
|
+
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
76
|
+
headers: { Accept: "application/json" },
|
|
77
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
78
|
+
}).then(
|
|
75
79
|
async (response) => {
|
|
76
80
|
if (!response.ok) {
|
|
77
81
|
throw new Error(`Discovery fetch for ${issuerUrl} failed: HTTP ${response.status}`);
|
|
@@ -128,6 +132,7 @@ function generateState() {
|
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
// src/token.ts
|
|
135
|
+
var FETCH_TIMEOUT_MS2 = 2500;
|
|
131
136
|
var TokenRequestError = class extends Error {
|
|
132
137
|
status;
|
|
133
138
|
error;
|
|
@@ -176,14 +181,29 @@ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAut
|
|
|
176
181
|
} else {
|
|
177
182
|
body.set("client_id", clientId);
|
|
178
183
|
}
|
|
179
|
-
return fetch(tokenEndpoint, {
|
|
184
|
+
return fetch(tokenEndpoint, {
|
|
185
|
+
method: "POST",
|
|
186
|
+
headers,
|
|
187
|
+
body: body.toString(),
|
|
188
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
async function postTokenRequestOrThrow(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
|
|
192
|
+
try {
|
|
193
|
+
return await postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
throw new TokenRequestError({
|
|
196
|
+
error: "network_failure",
|
|
197
|
+
errorDescription: error instanceof Error ? error.message : "Failed to reach the token endpoint"
|
|
198
|
+
});
|
|
199
|
+
}
|
|
180
200
|
}
|
|
181
201
|
async function readTokenResponseBody(response) {
|
|
182
202
|
return await response.json().catch(() => null);
|
|
183
203
|
}
|
|
184
204
|
async function exchangeAuthorizationCode(options) {
|
|
185
205
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
186
|
-
const response = await
|
|
206
|
+
const response = await postTokenRequestOrThrow(
|
|
187
207
|
discovery.token_endpoint,
|
|
188
208
|
options.clientId,
|
|
189
209
|
options.clientSecret,
|
|
@@ -203,7 +223,7 @@ async function exchangeAuthorizationCode(options) {
|
|
|
203
223
|
}
|
|
204
224
|
async function clientCredentialsGrant(options) {
|
|
205
225
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
206
|
-
const response = await
|
|
226
|
+
const response = await postTokenRequestOrThrow(
|
|
207
227
|
discovery.token_endpoint,
|
|
208
228
|
options.clientId,
|
|
209
229
|
options.clientSecret,
|
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
// src/discovery.ts
|
|
39
39
|
var import_jose = require("jose");
|
|
40
40
|
var DISCOVERY_CACHE_TTL_MS = 6e5;
|
|
41
|
+
var FETCH_TIMEOUT_MS = 2500;
|
|
41
42
|
var CACHE_MAX_ENTRIES = 100;
|
|
42
43
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
43
44
|
var discoveryPending = /* @__PURE__ */ new Map();
|
|
@@ -108,7 +109,10 @@ async function fetchDiscovery(issuerUrl) {
|
|
|
108
109
|
}
|
|
109
110
|
const pending = discoveryPending.get(issuerUrl);
|
|
110
111
|
if (pending) return pending;
|
|
111
|
-
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
112
|
+
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
113
|
+
headers: { Accept: "application/json" },
|
|
114
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
115
|
+
}).then(
|
|
112
116
|
async (response) => {
|
|
113
117
|
if (!response.ok) {
|
|
114
118
|
throw new Error(`Discovery fetch for ${issuerUrl} failed: HTTP ${response.status}`);
|
|
@@ -165,6 +169,7 @@ function generateState() {
|
|
|
165
169
|
}
|
|
166
170
|
|
|
167
171
|
// src/token.ts
|
|
172
|
+
var FETCH_TIMEOUT_MS2 = 2500;
|
|
168
173
|
var TokenRequestError = class extends Error {
|
|
169
174
|
status;
|
|
170
175
|
error;
|
|
@@ -213,14 +218,29 @@ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAut
|
|
|
213
218
|
} else {
|
|
214
219
|
body.set("client_id", clientId);
|
|
215
220
|
}
|
|
216
|
-
return fetch(tokenEndpoint, {
|
|
221
|
+
return fetch(tokenEndpoint, {
|
|
222
|
+
method: "POST",
|
|
223
|
+
headers,
|
|
224
|
+
body: body.toString(),
|
|
225
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
async function postTokenRequestOrThrow(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
|
|
229
|
+
try {
|
|
230
|
+
return await postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
throw new TokenRequestError({
|
|
233
|
+
error: "network_failure",
|
|
234
|
+
errorDescription: error instanceof Error ? error.message : "Failed to reach the token endpoint"
|
|
235
|
+
});
|
|
236
|
+
}
|
|
217
237
|
}
|
|
218
238
|
async function readTokenResponseBody(response) {
|
|
219
239
|
return await response.json().catch(() => null);
|
|
220
240
|
}
|
|
221
241
|
async function exchangeAuthorizationCode(options) {
|
|
222
242
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
223
|
-
const response = await
|
|
243
|
+
const response = await postTokenRequestOrThrow(
|
|
224
244
|
discovery.token_endpoint,
|
|
225
245
|
options.clientId,
|
|
226
246
|
options.clientSecret,
|
|
@@ -240,7 +260,7 @@ async function exchangeAuthorizationCode(options) {
|
|
|
240
260
|
}
|
|
241
261
|
async function clientCredentialsGrant(options) {
|
|
242
262
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
243
|
-
const response = await
|
|
263
|
+
const response = await postTokenRequestOrThrow(
|
|
244
264
|
discovery.token_endpoint,
|
|
245
265
|
options.clientId,
|
|
246
266
|
options.clientSecret,
|
package/dist/index.js
CHANGED
package/dist/next.cjs
CHANGED
|
@@ -29,6 +29,7 @@ var import_server = require("next/server");
|
|
|
29
29
|
// src/discovery.ts
|
|
30
30
|
var import_jose = require("jose");
|
|
31
31
|
var DISCOVERY_CACHE_TTL_MS = 6e5;
|
|
32
|
+
var FETCH_TIMEOUT_MS = 2500;
|
|
32
33
|
var CACHE_MAX_ENTRIES = 100;
|
|
33
34
|
var discoveryCache = /* @__PURE__ */ new Map();
|
|
34
35
|
var discoveryPending = /* @__PURE__ */ new Map();
|
|
@@ -99,7 +100,10 @@ async function fetchDiscovery(issuerUrl) {
|
|
|
99
100
|
}
|
|
100
101
|
const pending = discoveryPending.get(issuerUrl);
|
|
101
102
|
if (pending) return pending;
|
|
102
|
-
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
103
|
+
const promise = fetch(discoveryUrl(issuerUrl), {
|
|
104
|
+
headers: { Accept: "application/json" },
|
|
105
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
106
|
+
}).then(
|
|
103
107
|
async (response) => {
|
|
104
108
|
if (!response.ok) {
|
|
105
109
|
throw new Error(`Discovery fetch for ${issuerUrl} failed: HTTP ${response.status}`);
|
|
@@ -156,6 +160,7 @@ function generateState() {
|
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
// src/token.ts
|
|
163
|
+
var FETCH_TIMEOUT_MS2 = 2500;
|
|
159
164
|
var TokenRequestError = class extends Error {
|
|
160
165
|
status;
|
|
161
166
|
error;
|
|
@@ -204,14 +209,29 @@ async function postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAut
|
|
|
204
209
|
} else {
|
|
205
210
|
body.set("client_id", clientId);
|
|
206
211
|
}
|
|
207
|
-
return fetch(tokenEndpoint, {
|
|
212
|
+
return fetch(tokenEndpoint, {
|
|
213
|
+
method: "POST",
|
|
214
|
+
headers,
|
|
215
|
+
body: body.toString(),
|
|
216
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2)
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
async function postTokenRequestOrThrow(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params) {
|
|
220
|
+
try {
|
|
221
|
+
return await postTokenRequest(tokenEndpoint, clientId, clientSecret, clientAuthMethod, params);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
throw new TokenRequestError({
|
|
224
|
+
error: "network_failure",
|
|
225
|
+
errorDescription: error instanceof Error ? error.message : "Failed to reach the token endpoint"
|
|
226
|
+
});
|
|
227
|
+
}
|
|
208
228
|
}
|
|
209
229
|
async function readTokenResponseBody(response) {
|
|
210
230
|
return await response.json().catch(() => null);
|
|
211
231
|
}
|
|
212
232
|
async function exchangeAuthorizationCode(options) {
|
|
213
233
|
const discovery = await fetchDiscoveryForTokenRequest(options.issuer);
|
|
214
|
-
const response = await
|
|
234
|
+
const response = await postTokenRequestOrThrow(
|
|
215
235
|
discovery.token_endpoint,
|
|
216
236
|
options.clientId,
|
|
217
237
|
options.clientSecret,
|
|
@@ -400,6 +420,9 @@ function sanitizeReturnTo(returnTo) {
|
|
|
400
420
|
}
|
|
401
421
|
return returnTo.startsWith("/") ? returnTo : void 0;
|
|
402
422
|
}
|
|
423
|
+
function resolveRedirectUri(redirectUri, request) {
|
|
424
|
+
return typeof redirectUri === "function" ? redirectUri(request) : redirectUri;
|
|
425
|
+
}
|
|
403
426
|
function transactionCookieOptions(maxAge) {
|
|
404
427
|
return {
|
|
405
428
|
httpOnly: true,
|
|
@@ -425,7 +448,7 @@ function createLoginRoute(config) {
|
|
|
425
448
|
const discovery = await fetchDiscovery(config.issuer);
|
|
426
449
|
const authorizeUrl = new URL(discovery.authorization_endpoint);
|
|
427
450
|
authorizeUrl.searchParams.set("client_id", config.clientId);
|
|
428
|
-
authorizeUrl.searchParams.set("redirect_uri", config.redirectUri);
|
|
451
|
+
authorizeUrl.searchParams.set("redirect_uri", resolveRedirectUri(config.redirectUri, request));
|
|
429
452
|
authorizeUrl.searchParams.set("response_type", "code");
|
|
430
453
|
authorizeUrl.searchParams.set("scope", config.scope ?? "openid profile email roles");
|
|
431
454
|
authorizeUrl.searchParams.set("state", state);
|
|
@@ -479,8 +502,9 @@ function createCallbackRoute(config) {
|
|
|
479
502
|
issuer: config.issuer,
|
|
480
503
|
clientId: config.clientId,
|
|
481
504
|
clientSecret: config.clientSecret,
|
|
505
|
+
clientAuthMethod: config.clientAuthMethod,
|
|
482
506
|
code,
|
|
483
|
-
redirectUri: config.redirectUri,
|
|
507
|
+
redirectUri: resolveRedirectUri(config.redirectUri, request),
|
|
484
508
|
codeVerifier: transaction.codeVerifier
|
|
485
509
|
});
|
|
486
510
|
} catch (error) {
|
package/dist/next.d.cts
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as TokenSet, I as IdTokenClaims } from './verify-ggSzUrdC.cjs';
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { T as TokenEndpointAuthMethod, d as TokenSet, I as IdTokenClaims } from './verify-ggSzUrdC.cjs';
|
|
3
3
|
import { SealSecret } from './sealed.cjs';
|
|
4
4
|
import '@tdacorp/identity-authz';
|
|
5
5
|
import 'jose';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* A `redirect_uri` (RFC 6749 §3.1.2), either fixed or derived from the
|
|
9
|
+
* incoming request (e.g. `(request) => new URL('/api/auth/callback',
|
|
10
|
+
* request.nextUrl.origin).toString()`, for a deployment reachable at more
|
|
11
|
+
* than one origin -- a preview URL per branch, say).
|
|
12
|
+
*
|
|
13
|
+
* The resolved value MUST be identical on both the `createLoginRoute` call
|
|
14
|
+
* that starts a login and the `createCallbackRoute` call that finishes it
|
|
15
|
+
* (RFC 6749 §4.1.3 requires the token endpoint to see the same
|
|
16
|
+
* `redirect_uri` the authorization request used, and the identity server
|
|
17
|
+
* enforces this). A function form is only safe when it derives the same
|
|
18
|
+
* result from equivalent requests -- ordinarily true for `request.nextUrl
|
|
19
|
+
* .origin`, since the login and callback requests share one browser
|
|
20
|
+
* session and one domain, but not for anything that varies within that,
|
|
21
|
+
* e.g. a path segment.
|
|
22
|
+
*/
|
|
23
|
+
type RedirectUriConfig = string | ((request: NextRequest) => string);
|
|
7
24
|
interface CreateLoginRouteConfig {
|
|
8
25
|
issuer: string;
|
|
9
26
|
clientId: string;
|
|
10
|
-
|
|
27
|
+
/** See `RedirectUriConfig` -- must resolve to the same value
|
|
28
|
+
* `createCallbackRoute`'s own `redirectUri` does. */
|
|
29
|
+
redirectUri: RedirectUriConfig;
|
|
11
30
|
/** Space-separated OAuth scopes. Defaults to `"openid profile email
|
|
12
31
|
* roles"` -- `roles` is included in the default because without it the
|
|
13
32
|
* minted token carries no `roles` claim, and every `permits()` call
|
|
@@ -63,7 +82,19 @@ interface CreateCallbackRouteConfig {
|
|
|
63
82
|
clientId: string;
|
|
64
83
|
/** Omit for a public client authenticating via PKCE alone. */
|
|
65
84
|
clientSecret?: string;
|
|
66
|
-
|
|
85
|
+
/** How to send `clientSecret` to the token endpoint. Defaults to
|
|
86
|
+
* `'client_secret_basic'`, matching `exchangeAuthorizationCode`'s own
|
|
87
|
+
* default -- omitting this field changes nothing for an existing
|
|
88
|
+
* caller. Set it to `'client_secret_post'` if the relying party is
|
|
89
|
+
* registered on the identity platform for that method instead: sending
|
|
90
|
+
* Basic auth to a `client_secret_post`-only client gets `invalid_client`
|
|
91
|
+
* back, since the token endpoint never receives credentials in the form
|
|
92
|
+
* it expects. See `exchangeAuthorizationCode`'s own `clientAuthMethod`
|
|
93
|
+
* docs for the full reasoning. */
|
|
94
|
+
clientAuthMethod?: TokenEndpointAuthMethod;
|
|
95
|
+
/** See `RedirectUriConfig` -- must resolve to the same value
|
|
96
|
+
* `createLoginRoute`'s own `redirectUri` did. */
|
|
97
|
+
redirectUri: RedirectUriConfig;
|
|
67
98
|
cookieSecret: SealSecret;
|
|
68
99
|
transactionCookieName?: string;
|
|
69
100
|
/** Defaults to `clientId`, correct for a standard login where this app is
|
|
@@ -92,4 +123,4 @@ interface CreateCallbackRouteConfig {
|
|
|
92
123
|
* package stops there. */
|
|
93
124
|
declare function createCallbackRoute(config: CreateCallbackRouteConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
94
125
|
|
|
95
|
-
export { type CallbackError, type CreateCallbackRouteConfig, type CreateLoginRouteConfig, createCallbackRoute, createLoginRoute };
|
|
126
|
+
export { type CallbackError, type CreateCallbackRouteConfig, type CreateLoginRouteConfig, type RedirectUriConfig, createCallbackRoute, createLoginRoute };
|
package/dist/next.d.ts
CHANGED
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { d as TokenSet, I as IdTokenClaims } from './verify-ggSzUrdC.js';
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { T as TokenEndpointAuthMethod, d as TokenSet, I as IdTokenClaims } from './verify-ggSzUrdC.js';
|
|
3
3
|
import { SealSecret } from './sealed.js';
|
|
4
4
|
import '@tdacorp/identity-authz';
|
|
5
5
|
import 'jose';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* A `redirect_uri` (RFC 6749 §3.1.2), either fixed or derived from the
|
|
9
|
+
* incoming request (e.g. `(request) => new URL('/api/auth/callback',
|
|
10
|
+
* request.nextUrl.origin).toString()`, for a deployment reachable at more
|
|
11
|
+
* than one origin -- a preview URL per branch, say).
|
|
12
|
+
*
|
|
13
|
+
* The resolved value MUST be identical on both the `createLoginRoute` call
|
|
14
|
+
* that starts a login and the `createCallbackRoute` call that finishes it
|
|
15
|
+
* (RFC 6749 §4.1.3 requires the token endpoint to see the same
|
|
16
|
+
* `redirect_uri` the authorization request used, and the identity server
|
|
17
|
+
* enforces this). A function form is only safe when it derives the same
|
|
18
|
+
* result from equivalent requests -- ordinarily true for `request.nextUrl
|
|
19
|
+
* .origin`, since the login and callback requests share one browser
|
|
20
|
+
* session and one domain, but not for anything that varies within that,
|
|
21
|
+
* e.g. a path segment.
|
|
22
|
+
*/
|
|
23
|
+
type RedirectUriConfig = string | ((request: NextRequest) => string);
|
|
7
24
|
interface CreateLoginRouteConfig {
|
|
8
25
|
issuer: string;
|
|
9
26
|
clientId: string;
|
|
10
|
-
|
|
27
|
+
/** See `RedirectUriConfig` -- must resolve to the same value
|
|
28
|
+
* `createCallbackRoute`'s own `redirectUri` does. */
|
|
29
|
+
redirectUri: RedirectUriConfig;
|
|
11
30
|
/** Space-separated OAuth scopes. Defaults to `"openid profile email
|
|
12
31
|
* roles"` -- `roles` is included in the default because without it the
|
|
13
32
|
* minted token carries no `roles` claim, and every `permits()` call
|
|
@@ -63,7 +82,19 @@ interface CreateCallbackRouteConfig {
|
|
|
63
82
|
clientId: string;
|
|
64
83
|
/** Omit for a public client authenticating via PKCE alone. */
|
|
65
84
|
clientSecret?: string;
|
|
66
|
-
|
|
85
|
+
/** How to send `clientSecret` to the token endpoint. Defaults to
|
|
86
|
+
* `'client_secret_basic'`, matching `exchangeAuthorizationCode`'s own
|
|
87
|
+
* default -- omitting this field changes nothing for an existing
|
|
88
|
+
* caller. Set it to `'client_secret_post'` if the relying party is
|
|
89
|
+
* registered on the identity platform for that method instead: sending
|
|
90
|
+
* Basic auth to a `client_secret_post`-only client gets `invalid_client`
|
|
91
|
+
* back, since the token endpoint never receives credentials in the form
|
|
92
|
+
* it expects. See `exchangeAuthorizationCode`'s own `clientAuthMethod`
|
|
93
|
+
* docs for the full reasoning. */
|
|
94
|
+
clientAuthMethod?: TokenEndpointAuthMethod;
|
|
95
|
+
/** See `RedirectUriConfig` -- must resolve to the same value
|
|
96
|
+
* `createLoginRoute`'s own `redirectUri` did. */
|
|
97
|
+
redirectUri: RedirectUriConfig;
|
|
67
98
|
cookieSecret: SealSecret;
|
|
68
99
|
transactionCookieName?: string;
|
|
69
100
|
/** Defaults to `clientId`, correct for a standard login where this app is
|
|
@@ -92,4 +123,4 @@ interface CreateCallbackRouteConfig {
|
|
|
92
123
|
* package stops there. */
|
|
93
124
|
declare function createCallbackRoute(config: CreateCallbackRouteConfig): (request: NextRequest) => Promise<NextResponse>;
|
|
94
125
|
|
|
95
|
-
export { type CallbackError, type CreateCallbackRouteConfig, type CreateLoginRouteConfig, createCallbackRoute, createLoginRoute };
|
|
126
|
+
export { type CallbackError, type CreateCallbackRouteConfig, type CreateLoginRouteConfig, type RedirectUriConfig, createCallbackRoute, createLoginRoute };
|
package/dist/next.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
generateCodeVerifier,
|
|
6
6
|
generateState,
|
|
7
7
|
verifyIdToken
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-36WOXP7V.js";
|
|
9
9
|
import {
|
|
10
10
|
seal,
|
|
11
11
|
unseal
|
|
@@ -27,6 +27,9 @@ function sanitizeReturnTo(returnTo) {
|
|
|
27
27
|
}
|
|
28
28
|
return returnTo.startsWith("/") ? returnTo : void 0;
|
|
29
29
|
}
|
|
30
|
+
function resolveRedirectUri(redirectUri, request) {
|
|
31
|
+
return typeof redirectUri === "function" ? redirectUri(request) : redirectUri;
|
|
32
|
+
}
|
|
30
33
|
function transactionCookieOptions(maxAge) {
|
|
31
34
|
return {
|
|
32
35
|
httpOnly: true,
|
|
@@ -52,7 +55,7 @@ function createLoginRoute(config) {
|
|
|
52
55
|
const discovery = await fetchDiscovery(config.issuer);
|
|
53
56
|
const authorizeUrl = new URL(discovery.authorization_endpoint);
|
|
54
57
|
authorizeUrl.searchParams.set("client_id", config.clientId);
|
|
55
|
-
authorizeUrl.searchParams.set("redirect_uri", config.redirectUri);
|
|
58
|
+
authorizeUrl.searchParams.set("redirect_uri", resolveRedirectUri(config.redirectUri, request));
|
|
56
59
|
authorizeUrl.searchParams.set("response_type", "code");
|
|
57
60
|
authorizeUrl.searchParams.set("scope", config.scope ?? "openid profile email roles");
|
|
58
61
|
authorizeUrl.searchParams.set("state", state);
|
|
@@ -106,8 +109,9 @@ function createCallbackRoute(config) {
|
|
|
106
109
|
issuer: config.issuer,
|
|
107
110
|
clientId: config.clientId,
|
|
108
111
|
clientSecret: config.clientSecret,
|
|
112
|
+
clientAuthMethod: config.clientAuthMethod,
|
|
109
113
|
code,
|
|
110
|
-
redirectUri: config.redirectUri,
|
|
114
|
+
redirectUri: resolveRedirectUri(config.redirectUri, request),
|
|
111
115
|
codeVerifier: transaction.codeVerifier
|
|
112
116
|
});
|
|
113
117
|
} catch (error) {
|
package/package.json
CHANGED