@maronn-openid-connect/cli 0.7.1 → 0.8.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.
Files changed (67) hide show
  1. package/README.md +83 -7
  2. package/dist/frameworks/hono/index.d.ts.map +1 -1
  3. package/dist/frameworks/hono/index.js +18 -9
  4. package/dist/frameworks/hono/index.js.map +1 -1
  5. package/dist/frameworks/hono/pages.d.ts +7 -6
  6. package/dist/frameworks/hono/pages.d.ts.map +1 -1
  7. package/dist/frameworks/hono/pages.js +62 -44
  8. package/dist/frameworks/hono/pages.js.map +1 -1
  9. package/dist/frameworks/hono/templates.d.ts +19 -6
  10. package/dist/frameworks/hono/templates.d.ts.map +1 -1
  11. package/dist/frameworks/hono/templates.js +284 -304
  12. package/dist/frameworks/hono/templates.js.map +1 -1
  13. package/dist/frameworks/hono/views.d.ts +3 -0
  14. package/dist/frameworks/hono/views.d.ts.map +1 -0
  15. package/dist/frameworks/hono/views.js +458 -0
  16. package/dist/frameworks/hono/views.js.map +1 -0
  17. package/dist/frameworks/nextjs/authorize.d.ts +3 -0
  18. package/dist/frameworks/nextjs/authorize.d.ts.map +1 -0
  19. package/dist/frameworks/nextjs/authorize.js +757 -0
  20. package/dist/frameworks/nextjs/authorize.js.map +1 -0
  21. package/dist/frameworks/nextjs/ciba.d.ts +8 -0
  22. package/dist/frameworks/nextjs/ciba.d.ts.map +1 -0
  23. package/dist/frameworks/nextjs/ciba.js +591 -0
  24. package/dist/frameworks/nextjs/ciba.js.map +1 -0
  25. package/dist/frameworks/nextjs/conformance.d.ts +3 -0
  26. package/dist/frameworks/nextjs/conformance.d.ts.map +1 -0
  27. package/dist/frameworks/nextjs/conformance.js +2447 -0
  28. package/dist/frameworks/nextjs/conformance.js.map +1 -0
  29. package/dist/frameworks/nextjs/device.d.ts +8 -0
  30. package/dist/frameworks/nextjs/device.d.ts.map +1 -0
  31. package/dist/frameworks/nextjs/device.js +662 -0
  32. package/dist/frameworks/nextjs/device.js.map +1 -0
  33. package/dist/frameworks/nextjs/endpoints.d.ts +7 -0
  34. package/dist/frameworks/nextjs/endpoints.d.ts.map +1 -0
  35. package/dist/frameworks/nextjs/endpoints.js +673 -0
  36. package/dist/frameworks/nextjs/endpoints.js.map +1 -0
  37. package/dist/frameworks/nextjs/index.d.ts.map +1 -1
  38. package/dist/frameworks/nextjs/index.js +135 -2
  39. package/dist/frameworks/nextjs/index.js.map +1 -1
  40. package/dist/frameworks/nextjs/interaction.d.ts +13 -0
  41. package/dist/frameworks/nextjs/interaction.d.ts.map +1 -0
  42. package/dist/frameworks/nextjs/interaction.js +864 -0
  43. package/dist/frameworks/nextjs/interaction.js.map +1 -0
  44. package/dist/frameworks/nextjs/logout.d.ts +5 -0
  45. package/dist/frameworks/nextjs/logout.d.ts.map +1 -0
  46. package/dist/frameworks/nextjs/logout.js +271 -0
  47. package/dist/frameworks/nextjs/logout.js.map +1 -0
  48. package/dist/frameworks/nextjs/metadata.d.ts +6 -0
  49. package/dist/frameworks/nextjs/metadata.d.ts.map +1 -0
  50. package/dist/frameworks/nextjs/metadata.js +339 -0
  51. package/dist/frameworks/nextjs/metadata.js.map +1 -0
  52. package/dist/frameworks/nextjs/provider.d.ts +6 -0
  53. package/dist/frameworks/nextjs/provider.d.ts.map +1 -0
  54. package/dist/frameworks/nextjs/provider.js +797 -0
  55. package/dist/frameworks/nextjs/provider.js.map +1 -0
  56. package/dist/frameworks/nextjs/token.d.ts +7 -0
  57. package/dist/frameworks/nextjs/token.d.ts.map +1 -0
  58. package/dist/frameworks/nextjs/token.js +1337 -0
  59. package/dist/frameworks/nextjs/token.js.map +1 -0
  60. package/dist/frameworks/web-standard/templates.d.ts +1 -13
  61. package/dist/frameworks/web-standard/templates.d.ts.map +1 -1
  62. package/dist/frameworks/web-standard/templates.js +12 -1296
  63. package/dist/frameworks/web-standard/templates.js.map +1 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +38 -8
  66. package/dist/index.js.map +1 -1
  67. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../../src/frameworks/nextjs/interaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function nextJsLogoutConfigTemplate(): string;
2
+ export declare function nextJsLogoutScreensTemplate(): string;
3
+ export declare function nextJsLogoutRouteTemplate(corePkg: string): string;
4
+ export declare function nextJsLogoutApproveRouteTemplate(): string;
5
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../src/frameworks/nextjs/logout.ts"],"names":[],"mappings":"AAUA,wBAAgB,0BAA0B,IAAI,MAAM,CAenD;AAGD,wBAAgB,2BAA2B,IAAI,MAAM,CAuDpD;AAGD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA4IjE;AAGD,wBAAgB,gCAAgC,IAAI,MAAM,CAsDzD"}
@@ -0,0 +1,271 @@
1
+ import { EXPERIMENTAL_PACKAGE } from '../hono/templates.js';
2
+ const LOGOUT_PACKAGE = `${EXPERIMENTAL_PACKAGE}/rp-initiated-logout`;
3
+ export function nextJsLogoutConfigTemplate() {
4
+ return `/**
5
+ * EXPERIMENTAL — RP-Initiated Logout settings.
6
+ *
7
+ * postLogoutRedirectUris is the registry §3 checks against: client_id → the
8
+ * exact post_logout_redirect_uri values that client registered (a registry of
9
+ * its own — the authorize redirect_uris are NOT reused). A requested URI is used
10
+ * only on an exact string match for the client the id_token_hint verified for;
11
+ * everything else falls back to the logged-out screen (fail-closed). The
12
+ * default is empty, so no logout redirect happens until you register one here.
13
+ */
14
+ export const rpInitiatedLogoutConfig = {
15
+ postLogoutRedirectUris: {} as Record<string, string[]>,
16
+ };
17
+ `;
18
+ }
19
+ export function nextJsLogoutScreensTemplate() {
20
+ return `/**
21
+ * EXPERIMENTAL — the RP-Initiated Logout screens (RP-Initiated Logout 1.0 §2).
22
+ *
23
+ * Restyle the UI here. The confirmation form must keep posting csrf_token to
24
+ * /logout/approve: it is paired with the HttpOnly cookie the end_session
25
+ * endpoint mints.
26
+ */
27
+ import { escapeHtml, htmlResponse } from '../_oidc-provider/html';
28
+
29
+ /**
30
+ * The logout confirmation screen (§2 MUST when no valid id_token_hint is
31
+ * presented). The wording is the same on every path into it — no hint, an
32
+ * invalid or expired hint, another user's session, no session at all — so the
33
+ * page is no oracle for session state or for why the hint failed.
34
+ */
35
+ export function confirmationScreen(csrfToken: string, cookies: readonly string[]): Response {
36
+ return htmlResponse(
37
+ \`<!DOCTYPE html>
38
+ <html>
39
+ <head><title>Log out</title></head>
40
+ <body>
41
+ <h1>Log out</h1>
42
+ <p>Do you want to log out of the OpenID Provider?</p>
43
+ <p>If you did not request this, close this page.</p>
44
+ <form method="POST" action="/logout/approve">
45
+ <input type="hidden" name="csrf_token" value="\${escapeHtml(csrfToken)}" />
46
+ <button type="submit">Log out</button>
47
+ </form>
48
+ </body>
49
+ </html>\`,
50
+ { cookies },
51
+ );
52
+ }
53
+
54
+ /**
55
+ * The logged-out screen. It shows no End-User or client identifier, and its
56
+ * wording never depends on whether anything was actually deleted — varying it
57
+ * would make the page a session-existence oracle.
58
+ */
59
+ export function completedScreen(cookies: readonly string[]): Response {
60
+ return htmlResponse(
61
+ \`<!DOCTYPE html>
62
+ <html>
63
+ <head><title>Logged out</title></head>
64
+ <body>
65
+ <h1>Logged out</h1>
66
+ <p>You have been logged out.</p>
67
+ <p>You can close this page.</p>
68
+ </body>
69
+ </html>\`,
70
+ { cookies },
71
+ );
72
+ }
73
+ `;
74
+ }
75
+ export function nextJsLogoutRouteTemplate(corePkg) {
76
+ return `/**
77
+ * EXPERIMENTAL — end_session_endpoint (OpenID Connect RP-Initiated Logout 1.0).
78
+ *
79
+ * Generated because the OP was created with \`--enable rp-initiated-logout\`.
80
+ * Backed by ${EXPERIMENTAL_PACKAGE}, whose API is NOT stable: it may change in a
81
+ * breaking way between releases. Do not build production code on it without
82
+ * pinning the version.
83
+ *
84
+ * The RP sends the user agent here (GET or POST, §2 MUST) to end the OP browser
85
+ * session. A request whose id_token_hint verifies against this OP's keys AND
86
+ * matches the current session's End-User logs out immediately; every other
87
+ * request — no hint, an invalid or expired hint, a client_id that mismatches the
88
+ * hint audience, no session, another user's session — falls to one shared
89
+ * confirmation screen (§2 MUST; §7: an unauthenticated logout link would
90
+ * otherwise be a denial-of-service primitive). The failure reason is never
91
+ * disclosed: it would turn this endpoint into an oracle for session state.
92
+ *
93
+ * ## Why the confirmation needs a cookie + token pair
94
+ *
95
+ * Approving the confirmation ends a session, so a forged cross-site POST must
96
+ * not drive it. The confirmation screen hands this browser a fresh secret
97
+ * twice: in an HttpOnly cookie and in the form's hidden csrf_token, and
98
+ * /logout/approve runs only when both come back equal. The cookie also carries
99
+ * the OP-computed post-logout redirect, so the id_token_hint is never
100
+ * round-tripped through the HTML page.
101
+ */
102
+ import { NextResponse, type NextRequest } from 'next/server';
103
+ import {
104
+ decideLogoutFlow,
105
+ extractIdTokenHintAudience,
106
+ parseEndSessionRequest,
107
+ resolvePostLogoutRedirect,
108
+ } from '${LOGOUT_PACKAGE}';
109
+ import { IdTokenHintError, generateRandomString, validateIdTokenHint } from '${corePkg}';
110
+ import { readFormFields } from '../_oidc-provider/http';
111
+ import { config, idTokenHintJwks, loadSigningKeys, stores } from '../_oidc-provider/provider';
112
+ import {
113
+ buildClearedSessionCookie,
114
+ buildLogoutConfirmationCookie,
115
+ parseSessionId,
116
+ } from '../_oidc-provider/store';
117
+ import { rpInitiatedLogoutConfig } from './config';
118
+ import { completedScreen, confirmationScreen } from './screens';
119
+
120
+ export const dynamic = 'force-dynamic';
121
+ export const runtime = 'nodejs';
122
+
123
+ export async function GET(request: NextRequest): Promise<Response> {
124
+ return endSession(request, request.nextUrl.searchParams);
125
+ }
126
+
127
+ /** §2: POST carries the same parameters in an application/x-www-form-urlencoded body. */
128
+ export async function POST(request: Request): Promise<Response> {
129
+ const params = new URLSearchParams();
130
+ for (const [name, value] of await readFormFields(request)) {
131
+ if (typeof value === 'string') params.append(name, value);
132
+ }
133
+ return endSession(request, params);
134
+ }
135
+
136
+ async function endSession(request: Request, params: URLSearchParams): Promise<Response> {
137
+ const endSessionRequest = parseEndSessionRequest(params);
138
+ // logout_hint and ui_locales are accepted but unused (OPTIONAL, §2). The hint
139
+ // is never logged — it can identify the End-User — and neither is the
140
+ // id_token_hint value itself.
141
+
142
+ // §2: verify the hint (signature / iss / aud / exp) against the keys
143
+ // id_token_hint is verified with elsewhere. The expected audience is the
144
+ // client_id parameter when present, otherwise it is read — unverified — from
145
+ // the hint payload; trust comes from validateIdTokenHint afterwards.
146
+ let verifiedHint: { sub: string; [key: string]: unknown } | null = null;
147
+ let expectedAudience: string | null = null;
148
+ if (endSessionRequest.idTokenHint !== undefined) {
149
+ expectedAudience =
150
+ endSessionRequest.clientId ?? extractIdTokenHintAudience(endSessionRequest.idTokenHint);
151
+ if (expectedAudience !== null) {
152
+ try {
153
+ verifiedHint = await validateIdTokenHint(endSessionRequest.idTokenHint, {
154
+ expectedIss: config.issuer,
155
+ expectedAud: expectedAudience,
156
+ jwks: await idTokenHintJwks(await loadSigningKeys()),
157
+ });
158
+ } catch (error) {
159
+ // An expired, tampered or foreign hint just fails to prove logout
160
+ // authority, so the request falls to the confirmation path (§2 MUST)
161
+ // with no reason disclosed. Anything else (the keys failing to load)
162
+ // is rethrown: masking an outage as "invalid hint" would silently turn
163
+ // every logout into a confirmation.
164
+ if (!(error instanceof IdTokenHintError)) throw error;
165
+ verifiedHint = null;
166
+ }
167
+ }
168
+ }
169
+
170
+ const sessionId = parseSessionId(request.headers.get('Cookie'));
171
+ const session = sessionId ? await stores.browserSessionStore.get(sessionId) : undefined;
172
+
173
+ const decision = decideLogoutFlow({
174
+ verifiedHint,
175
+ expectedAudience,
176
+ clientIdParam: endSessionRequest.clientId,
177
+ sessionSubject: session ? session.subject : null,
178
+ });
179
+
180
+ // §3: redirect only to the verified client's exactly-matching registered URI,
181
+ // with state appended. Resolved before the branch because the confirmation
182
+ // flow honors the same result after approval.
183
+ const redirectTo = resolvePostLogoutRedirect({
184
+ postLogoutRedirectUri: endSessionRequest.postLogoutRedirectUri,
185
+ state: endSessionRequest.state,
186
+ verifiedClientId: decision.verifiedClientId,
187
+ registeredUris:
188
+ decision.verifiedClientId === null
189
+ ? []
190
+ : rpInitiatedLogoutConfig.postLogoutRedirectUris[decision.verifiedClientId] ?? [],
191
+ });
192
+
193
+ if (decision.requiresConfirmation) {
194
+ // §2 MUST: ask first. Nothing is deleted yet. The minted secret pairs the
195
+ // HttpOnly cookie with the form's hidden csrf_token; the redirect target
196
+ // rides inside the cookie.
197
+ const csrfSecret = generateRandomString(32);
198
+ return confirmationScreen(csrfSecret, [buildLogoutConfirmationCookie({ csrfSecret, redirectTo })]);
199
+ }
200
+
201
+ // Immediate logout: a valid hint for the current session's End-User (§2).
202
+ // Delete the store entry and expire the cookie together.
203
+ if (sessionId) {
204
+ await stores.browserSessionStore.delete(sessionId);
205
+ }
206
+ const cookies = [buildClearedSessionCookie()];
207
+ if (redirectTo !== null) {
208
+ const response = NextResponse.redirect(redirectTo, 302);
209
+ for (const cookie of cookies) response.headers.append('Set-Cookie', cookie);
210
+ return response;
211
+ }
212
+ return completedScreen(cookies);
213
+ }
214
+ `;
215
+ }
216
+ export function nextJsLogoutApproveRouteTemplate() {
217
+ return `/**
218
+ * EXPERIMENTAL — RP-Initiated Logout confirmation approve.
219
+ *
220
+ * Runs only for the browser that saw the confirmation screen: the HttpOnly
221
+ * cookie and the hidden csrf_token must present the same secret (neither alone
222
+ * is accepted). On success the session is deleted and the redirect decided when
223
+ * the screen was shown — carried in the cookie, never in the form — is honored
224
+ * (§3).
225
+ *
226
+ * Backed by ${EXPERIMENTAL_PACKAGE}, whose API is NOT stable.
227
+ */
228
+ import { NextResponse } from 'next/server';
229
+ import { errorPage } from '../../_oidc-provider/html';
230
+ import { readFormFields } from '../../_oidc-provider/http';
231
+ import { stores } from '../../_oidc-provider/provider';
232
+ import {
233
+ buildClearedLogoutConfirmationCookie,
234
+ buildClearedSessionCookie,
235
+ parseLogoutConfirmation,
236
+ parseSessionId,
237
+ } from '../../_oidc-provider/store';
238
+ import { completedScreen } from '../screens';
239
+
240
+ export const dynamic = 'force-dynamic';
241
+ export const runtime = 'nodejs';
242
+
243
+ export async function POST(request: Request): Promise<Response> {
244
+ const csrfToken = String((await readFormFields(request)).get('csrf_token') ?? '');
245
+ const cookieHeader = request.headers.get('Cookie');
246
+
247
+ const confirmation = parseLogoutConfirmation(cookieHeader);
248
+ if (confirmation === null || csrfToken === '' || confirmation.csrfSecret !== csrfToken) {
249
+ // Forged, replayed or expired confirmation: nothing is deleted. This is a
250
+ // browser surface, so the answer is the error page, not OAuth error JSON.
251
+ return errorPage('Invalid logout confirmation', 400);
252
+ }
253
+
254
+ // The End-User explicitly approved (§2). When the session is already gone
255
+ // there is nothing to delete and the answer is the same either way — the
256
+ // confirmation flow is no oracle for whether a session existed.
257
+ const sessionId = parseSessionId(cookieHeader);
258
+ if (sessionId) {
259
+ await stores.browserSessionStore.delete(sessionId);
260
+ }
261
+ const cookies = [buildClearedSessionCookie(), buildClearedLogoutConfirmationCookie()];
262
+ if (confirmation.redirectTo !== null) {
263
+ const response = NextResponse.redirect(confirmation.redirectTo, 302);
264
+ for (const cookie of cookies) response.headers.append('Set-Cookie', cookie);
265
+ return response;
266
+ }
267
+ return completedScreen(cookies);
268
+ }
269
+ `;
270
+ }
271
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/frameworks/nextjs/logout.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,cAAc,GAAG,GAAG,oBAAoB,sBAAsB,CAAC;AAGrE,MAAM,UAAU,0BAA0B;IACxC,OAAO;;;;;;;;;;;;;CAaR,CAAC;AACF,CAAC;AAGD,MAAM,UAAU,2BAA2B;IACzC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDR,CAAC;AACF,CAAC;AAGD,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,OAAO;;;;eAIM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BzB,cAAc;+EACuD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyGrF,CAAC;AACF,CAAC;AAGD,MAAM,UAAU,gCAAgC;IAC9C,OAAO;;;;;;;;;eASM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ClC,CAAC;AACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { OidcFeatureConfig } from '../../features.js';
2
+ export declare function nextJsSupportedGrantTypes(features: OidcFeatureConfig): string[];
3
+ export declare function nextJsSupportedScopes(features: OidcFeatureConfig, scopes: string[]): string[];
4
+ export declare function nextJsDiscoveryRouteTemplate(corePkg: string, features?: OidcFeatureConfig, scopes?: string[]): string;
5
+ export declare function nextJsJwksRouteTemplate(corePkg: string): string;
6
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../src/frameworks/nextjs/metadata.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAQ3D,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAiB/E;AAMD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAU7F;AAGD,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,iBAAoC,EAC9C,MAAM,GAAE,MAAM,EAAO,GACpB,MAAM,CAmPR;AAGD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA0E/D"}
@@ -0,0 +1,339 @@
1
+ import { DEFAULT_FEATURES } from '../../features.js';
2
+ export function nextJsSupportedGrantTypes(features) {
3
+ return [
4
+ 'authorization_code',
5
+ ...(features.refreshToken ? ['refresh_token'] : []),
6
+ ...(features.tokenExchange || features.idJag
7
+ ? ['urn:ietf:params:oauth:grant-type:token-exchange']
8
+ : []),
9
+ ...(features.idJag ? ['urn:ietf:params:oauth:grant-type:jwt-bearer'] : []),
10
+ ...(features.deviceAuthorizationGrant
11
+ ? ['urn:ietf:params:oauth:grant-type:device_code']
12
+ : []),
13
+ ...(features.ciba ? ['urn:openid:params:grant-type:ciba'] : []),
14
+ ];
15
+ }
16
+ export function nextJsSupportedScopes(features, scopes) {
17
+ return [
18
+ 'openid',
19
+ 'profile',
20
+ 'email',
21
+ 'address',
22
+ 'phone',
23
+ ...(features.refreshToken ? ['offline_access'] : []),
24
+ ...scopes,
25
+ ];
26
+ }
27
+ export function nextJsDiscoveryRouteTemplate(corePkg, features = DEFAULT_FEATURES, scopes = []) {
28
+ const customScopesDeclared = scopes.length > 0;
29
+ const customScopeImport = customScopesDeclared
30
+ ? `
31
+ import { SUPPORTED_SCOPES } from '../../_oidc-provider/scopes';`
32
+ : '';
33
+ const scopesSupportedEntry = customScopesDeclared
34
+ ? ` // OIDC Discovery 1.0 §3: scopes_supported is this OP's scope allow list —
35
+ // the standard scopes plus the custom ones declared with --scope (see
36
+ // scopes.ts). It lists what the provider accepts, not what a particular
37
+ // End-User is granted (resolveGrantableScopes decides that).
38
+ scopesSupported: [...SUPPORTED_SCOPES],
39
+ `
40
+ : features.refreshToken
41
+ ? ` // OIDC Core 1.0 §11: offline_access is advertised so relying parties (and the
42
+ // OIDF Conformance Suite's oidcc-refresh-token module) know they may request
43
+ // refresh tokens via 'scope=openid offline_access' with prompt=consent.
44
+ // It is a refresh-token request scope, not a claim scope, so no matching
45
+ // entry is added to claimsSupported.
46
+ scopesSupported: ['openid', 'profile', 'email', 'address', 'phone', 'offline_access'],
47
+ `
48
+ : ` // The refresh_token feature is disabled, so offline_access is not advertised
49
+ // (OIDC Core 1.0 §11: it would never be granted by this provider).
50
+ scopesSupported: ['openid', 'profile', 'email', 'address', 'phone'],
51
+ `;
52
+ const supportedGrantTypes = nextJsSupportedGrantTypes(features).map((grantType) => `'${grantType}'`);
53
+ const requestObjectMetadata = features.requestObject
54
+ ? ` // OIDC Core 1.0 §6.1 / OIDC Discovery 1.0 §3: a signed Request Object by value
55
+ // is supported (verified against the client's registered JWKS). request_uri
56
+ // (§6.2) is not, so it is advertised as false explicitly — Discovery defaults
57
+ // request_uri_parameter_supported to true when omitted. 'none' is added only
58
+ // when unsigned objects are accepted for Basic OP conformance compatibility.
59
+ requestParameterSupported: true,
60
+ requestUriParameterSupported: false,
61
+ requestObjectSigningAlgValuesSupported: config.allowUnsignedRequestObject
62
+ ? ['RS256', 'none']
63
+ : ['RS256'],
64
+ `
65
+ : ` // OIDC Core 1.0 §6.3: the request parameter (Request Object) is disabled in
66
+ // this generated provider, so request_parameter_supported is advertised as
67
+ // false. request_uri (§6.2) remains unsupported as well.
68
+ requestParameterSupported: false,
69
+ requestUriParameterSupported: false,
70
+ `;
71
+ const rfc8414Comment = features.introspection && features.revocation
72
+ ? ` // RFC 8414 — both endpoints require client authentication.
73
+ `
74
+ : features.introspection || features.revocation
75
+ ? ` // RFC 8414 — the endpoint requires client authentication.
76
+ `
77
+ : '';
78
+ const introspectionMetadata = features.introspection
79
+ ? ` introspectionEndpoint: \`\${issuer}/introspect\`,
80
+ introspectionEndpointAuthMethodsSupported: [
81
+ 'client_secret_basic',
82
+ 'client_secret_post',
83
+ ],
84
+ `
85
+ : '';
86
+ const revocationMetadata = features.revocation
87
+ ? ` revocationEndpoint: \`\${issuer}/revoke\`,
88
+ revocationEndpointAuthMethodsSupported: [
89
+ 'client_secret_basic',
90
+ 'client_secret_post',
91
+ ],
92
+ `
93
+ : '';
94
+ const responseModesSupportedEntry = features.jarm
95
+ ? ` // OAuth 2.0 Multiple Response Type Encoding Practices §2 / OIDC Discovery 1.0
96
+ // §3: the code flow answers via query. EXPERIMENTAL (JARM §4): this provider
97
+ // was generated with --enable jarm, so the JWT-secured query modes are
98
+ // advertised alongside it.
99
+ responseModesSupported: ['query', 'query.jwt', 'jwt'],`
100
+ : ` // OAuth 2.0 Multiple Response Type Encoding Practices §2 / OIDC Discovery 1.0
101
+ // §3: the OP only implements the authorization code flow, whose response is
102
+ // returned via query, so response_modes_supported is pinned to ['query'].
103
+ responseModesSupported: ['query'],`;
104
+ const parImport = features.par
105
+ ? `
106
+ import { parConfig } from '../../par/config';`
107
+ : '';
108
+ const extensionMetadata = [
109
+ ...(features.par
110
+ ? [` // EXPERIMENTAL — RFC 9126 §5. require_pushed_authorization_requests is only
111
+ // advertised when PAR is actually enforced (its default is false).
112
+ pushed_authorization_request_endpoint: \`\${issuer}/par\`,
113
+ ...(parConfig.requirePushedAuthorizationRequests
114
+ ? { require_pushed_authorization_requests: true }
115
+ : {}),`]
116
+ : []),
117
+ ...(features.deviceAuthorizationGrant
118
+ ? [` // EXPERIMENTAL — RFC 8628 §4.
119
+ device_authorization_endpoint: \`\${issuer}/device_authorization\`,`]
120
+ : []),
121
+ ...(features.ciba
122
+ ? [` // EXPERIMENTAL — CIBA Core 1.0 §4. Only the poll delivery mode is offered.
123
+ backchannel_token_delivery_modes_supported: ['poll'],
124
+ backchannel_authentication_endpoint: \`\${issuer}/backchannel_authentication\`,`]
125
+ : []),
126
+ ...(features.jarm
127
+ ? [` // EXPERIMENTAL — JARM §4. The response JWT is always signed with RS256 (JARM
128
+ // §3: the default for a client that registered no
129
+ // authorization_signed_response_alg).
130
+ authorization_signing_alg_values_supported: ['RS256'],`]
131
+ : []),
132
+ ...(features.idJag
133
+ ? [` // EXPERIMENTAL — ID-JAG draft §7.1 / §7.2: this OP issues ID-JAGs via token
134
+ // exchange and redeems them on the jwt-bearer grant. Which issuers and
135
+ // audiences are trusted is local policy and is not disclosed (draft §9.4).
136
+ identity_chaining_requested_token_types_supported: ['urn:ietf:params:oauth:token-type:id-jag'],
137
+ authorization_grant_profiles_supported: ['urn:ietf:params:oauth:grant-profile:id-jag'],`]
138
+ : []),
139
+ ...(features.introspection && features.jwtIntrospectionResponse
140
+ ? [` // EXPERIMENTAL — RFC 9701 §7. The introspection response JWT is always signed
141
+ // with RS256 (§6: the default for a client that registered no
142
+ // introspection_signed_response_alg).
143
+ introspection_signing_alg_values_supported: ['RS256'],`]
144
+ : []),
145
+ ...(features.rpInitiatedLogout
146
+ ? [` // EXPERIMENTAL — RP-Initiated Logout 1.0 §2.1.
147
+ end_session_endpoint: \`\${issuer}/logout\`,`]
148
+ : []),
149
+ ];
150
+ const extensionMetadataBlock = extensionMetadata.length > 0
151
+ ? `\n${extensionMetadata.join('\n')}`
152
+ : '';
153
+ return `/**
154
+ * OpenID Provider Configuration (OIDC Discovery 1.0 §4).
155
+ */
156
+ import { buildProviderMetadata, getJwaAlgorithm } from '${corePkg}';
157
+ import { config, loadSigningKeys } from '../../_oidc-provider/provider';
158
+ import {
159
+ corsPreflight,
160
+ publicCors,
161
+ signingKeysUnavailable,
162
+ withCors,
163
+ } from '../../_oidc-provider/http';${parImport}${customScopeImport}
164
+
165
+ export const dynamic = 'force-dynamic';
166
+ export const runtime = 'nodejs';
167
+
168
+ export async function GET(request: Request): Promise<Response> {
169
+ return withCors(request, publicCors, await providerMetadata());
170
+ }
171
+
172
+ export function OPTIONS(request: Request): Response {
173
+ return corsPreflight(request, publicCors);
174
+ }
175
+
176
+ async function providerMetadata(): Promise<Response> {
177
+ const keys = await loadSigningKeys().catch(() => null);
178
+ if (!keys) return signingKeysUnavailable();
179
+
180
+ const issuer = config.issuer;
181
+ const metadata = buildProviderMetadata({
182
+ issuer,
183
+ authorizationEndpoint: \`\${issuer}/authorize\`,
184
+ tokenEndpoint: \`\${issuer}/token\`,
185
+ jwksUri: \`\${issuer}/.well-known/jwks.json\`,
186
+ responseTypesSupported: ['code'],
187
+ ${responseModesSupportedEntry}
188
+ subjectTypesSupported: ['public'],
189
+ // OIDC Core 1.0 §15.1: id_token_signing_alg_values_supported is derived from
190
+ // every registered ID Token key, so a mixed RS256 + ES256 set is advertised
191
+ // as such (buildProviderMetadata enforces that RS256 is present).
192
+ idTokenSigningKeys: keys.idToken.registered.map((key) => key.privateKey),
193
+ userinfoEndpoint: \`\${issuer}/userinfo\`,
194
+ ${scopesSupportedEntry} // OIDC Discovery 1.0 §3 / Core 1.0 §5.6: this OP produces Normal Claims only
195
+ // (no _claim_names / _claim_sources).
196
+ claimTypesSupported: ['normal'],
197
+ claimsSupported: [
198
+ 'sub',
199
+ 'iss',
200
+ 'aud',
201
+ 'exp',
202
+ 'iat',
203
+ // OIDC Core 1.0 §2 / §3.1.3.6: ID Token protocol claims the OP issues.
204
+ // c_hash is omitted on purpose: the Hybrid flow is not implemented.
205
+ 'auth_time',
206
+ 'nonce',
207
+ 'acr',
208
+ 'amr',
209
+ 'azp',
210
+ 'at_hash',
211
+ 'name',
212
+ 'family_name',
213
+ 'given_name',
214
+ 'middle_name',
215
+ 'nickname',
216
+ 'preferred_username',
217
+ 'profile',
218
+ 'picture',
219
+ 'website',
220
+ 'gender',
221
+ 'birthdate',
222
+ 'zoneinfo',
223
+ 'locale',
224
+ 'updated_at',
225
+ 'email',
226
+ 'email_verified',
227
+ 'address',
228
+ 'phone_number',
229
+ 'phone_number_verified',
230
+ ],
231
+ grantTypesSupported: [${supportedGrantTypes.join(', ')}],
232
+ // RFC 6749 §2.1 / OAuth 2.1 §2.4: 'none' advertises that public clients
233
+ // (no client_secret) are accepted at the token endpoint.
234
+ tokenEndpointAuthMethodsSupported: [
235
+ 'client_secret_basic',
236
+ 'client_secret_post',
237
+ 'none',
238
+ ],
239
+ // OIDC Core 1.0 §5.3.2: the algs the registered UserInfo keys can sign with,
240
+ // so clients relying on userinfo_signed_response_alg can trust the metadata.
241
+ userinfoSigningAlgValuesSupported: [
242
+ ...new Set(keys.userinfo.registered.map((key) => getJwaAlgorithm(key.privateKey))),
243
+ ],
244
+ ${requestObjectMetadata} // OIDC Discovery 1.0 §3 / Core 1.0 §5.5: the claims request parameter is
245
+ // implemented for both the ID Token and UserInfo.
246
+ claimsParameterSupported: true,
247
+ // RFC 9207 §3: every authorization response carries iss.
248
+ authorizationResponseIssParameterSupported: true,
249
+ ${rfc8414Comment}${introspectionMetadata}${revocationMetadata} });
250
+
251
+ // RFC 8414 §3.2 / RFC 9111 §5.2: discovery metadata is cacheable; 3600s, the
252
+ // same freshness lifetime as the JWKS endpoint.
253
+ return Response.json(
254
+ {
255
+ ...metadata,
256
+ // RFC 7636 / OAuth 2.1: not an OIDC Discovery field, so added here.
257
+ code_challenge_methods_supported: ['S256'],${extensionMetadataBlock}
258
+ },
259
+ { headers: { 'Cache-Control': 'public, max-age=3600' } },
260
+ );
261
+ }
262
+ `;
263
+ }
264
+ export function nextJsJwksRouteTemplate(corePkg) {
265
+ return `/**
266
+ * JWKS endpoint: the public keys every OP-signed token is verified with.
267
+ *
268
+ * All three key sets are published (general, ID Token, UserInfo) including
269
+ * rotated-out keys, so tokens signed before a rotation keep verifying until
270
+ * they expire. A kid appears once; of the keys without a kid only the most
271
+ * recently added one is published.
272
+ */
273
+ import { exportJwks, extractAlgorithmParamsFromJwk, type SigningKey } from '${corePkg}';
274
+ import { loadSigningKeys } from '../../_oidc-provider/provider';
275
+ import {
276
+ corsPreflight,
277
+ publicCors,
278
+ signingKeysUnavailable,
279
+ withCors,
280
+ } from '../../_oidc-provider/http';
281
+
282
+ export const dynamic = 'force-dynamic';
283
+ export const runtime = 'nodejs';
284
+
285
+ export async function GET(request: Request): Promise<Response> {
286
+ return withCors(request, publicCors, await jwks());
287
+ }
288
+
289
+ export function OPTIONS(request: Request): Response {
290
+ return corsPreflight(request, publicCors);
291
+ }
292
+
293
+ async function jwks(): Promise<Response> {
294
+ const keys = await loadSigningKeys().catch(() => null);
295
+ if (!keys) return signingKeysUnavailable();
296
+
297
+ const published = publishedKeys([
298
+ ...keys.general.registered,
299
+ ...keys.idToken.registered,
300
+ ...keys.userinfo.registered,
301
+ ]);
302
+ const entries = await Promise.all(
303
+ published.map(async (key) => ({
304
+ publicKey: await crypto.subtle.importKey(
305
+ 'jwk',
306
+ key.publicJwk,
307
+ extractAlgorithmParamsFromJwk(key.publicJwk),
308
+ true,
309
+ ['verify'],
310
+ ),
311
+ keyId: key.keyId,
312
+ })),
313
+ );
314
+
315
+ return Response.json(await exportJwks(entries), {
316
+ headers: { 'Cache-Control': 'public, max-age=3600' },
317
+ });
318
+ }
319
+
320
+ /**
321
+ * The first key of every kid, plus the last key that has no kid (the most
322
+ * recent one wins, since rotation appends).
323
+ */
324
+ function publishedKeys(candidates: readonly SigningKey[]): SigningKey[] {
325
+ let lastWithoutKid = -1;
326
+ candidates.forEach((key, index) => {
327
+ if (key.keyId === undefined) lastWithoutKid = index;
328
+ });
329
+ const seenKids = new Set<string>();
330
+ return candidates.filter((key, index) => {
331
+ if (key.keyId === undefined) return index === lastWithoutKid;
332
+ if (seenKids.has(key.keyId)) return false;
333
+ seenKids.add(key.keyId);
334
+ return true;
335
+ });
336
+ }
337
+ `;
338
+ }
339
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/frameworks/nextjs/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { OidcFeatureConfig } from '../../features.js';
2
+ export declare function nextJsProviderTemplate(corePkg: string, features?: OidcFeatureConfig): string;
3
+ export declare function nextJsStorageBackendTemplate(): string;
4
+ export declare function nextJsHttpTemplate(): string;
5
+ export declare function nextJsHtmlTemplate(): string;
6
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/frameworks/nextjs/provider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAO3D,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,iBAAoC,GAC7C,MAAM,CA6XR;AAMD,wBAAgB,4BAA4B,IAAI,MAAM,CA2LrD;AAQD,wBAAgB,kBAAkB,IAAI,MAAM,CA+K3C;AAOD,wBAAgB,kBAAkB,IAAI,MAAM,CAwD3C"}