@tdacorp/identity-client 0.2.5 → 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/next.cjs +6 -2
- package/dist/next.d.cts +36 -5
- package/dist/next.d.ts +36 -5
- package/dist/next.js +6 -2
- 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
|
package/dist/next.cjs
CHANGED
|
@@ -420,6 +420,9 @@ function sanitizeReturnTo(returnTo) {
|
|
|
420
420
|
}
|
|
421
421
|
return returnTo.startsWith("/") ? returnTo : void 0;
|
|
422
422
|
}
|
|
423
|
+
function resolveRedirectUri(redirectUri, request) {
|
|
424
|
+
return typeof redirectUri === "function" ? redirectUri(request) : redirectUri;
|
|
425
|
+
}
|
|
423
426
|
function transactionCookieOptions(maxAge) {
|
|
424
427
|
return {
|
|
425
428
|
httpOnly: true,
|
|
@@ -445,7 +448,7 @@ function createLoginRoute(config) {
|
|
|
445
448
|
const discovery = await fetchDiscovery(config.issuer);
|
|
446
449
|
const authorizeUrl = new URL(discovery.authorization_endpoint);
|
|
447
450
|
authorizeUrl.searchParams.set("client_id", config.clientId);
|
|
448
|
-
authorizeUrl.searchParams.set("redirect_uri", config.redirectUri);
|
|
451
|
+
authorizeUrl.searchParams.set("redirect_uri", resolveRedirectUri(config.redirectUri, request));
|
|
449
452
|
authorizeUrl.searchParams.set("response_type", "code");
|
|
450
453
|
authorizeUrl.searchParams.set("scope", config.scope ?? "openid profile email roles");
|
|
451
454
|
authorizeUrl.searchParams.set("state", state);
|
|
@@ -499,8 +502,9 @@ function createCallbackRoute(config) {
|
|
|
499
502
|
issuer: config.issuer,
|
|
500
503
|
clientId: config.clientId,
|
|
501
504
|
clientSecret: config.clientSecret,
|
|
505
|
+
clientAuthMethod: config.clientAuthMethod,
|
|
502
506
|
code,
|
|
503
|
-
redirectUri: config.redirectUri,
|
|
507
|
+
redirectUri: resolveRedirectUri(config.redirectUri, request),
|
|
504
508
|
codeVerifier: transaction.codeVerifier
|
|
505
509
|
});
|
|
506
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
|
@@ -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