actor-gate 0.1.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/package.json +25 -0
- package/src/config/base-config.d.ts +17 -0
- package/src/config/base-config.js +33 -0
- package/src/config/index.d.ts +5 -0
- package/src/config/index.js +5 -0
- package/src/config/nextjs-public-config.d.ts +46 -0
- package/src/config/nextjs-public-config.js +89 -0
- package/src/config/nextjs-server-config.d.ts +32 -0
- package/src/config/nextjs-server-config.js +10 -0
- package/src/config/react-client.d.ts +23 -0
- package/src/config/react-client.js +69 -0
- package/src/config/react-config.d.ts +18 -0
- package/src/config/react-config.js +38 -0
- package/src/core/adapters/access-token-revocation-adapter.d.ts +8 -0
- package/src/core/adapters/access-token-revocation-adapter.js +1 -0
- package/src/core/adapters/access-token-transport-adapter.d.ts +15 -0
- package/src/core/adapters/access-token-transport-adapter.js +1 -0
- package/src/core/adapters/authorization-code-adapter.d.ts +21 -0
- package/src/core/adapters/authorization-code-adapter.js +1 -0
- package/src/core/adapters/authorization-hooks.d.ts +13 -0
- package/src/core/adapters/authorization-hooks.js +1 -0
- package/src/core/adapters/index.d.ts +14 -0
- package/src/core/adapters/index.js +1 -0
- package/src/core/adapters/login-method-adapter.d.ts +7 -0
- package/src/core/adapters/login-method-adapter.js +1 -0
- package/src/core/adapters/oauth-client-adapter.d.ts +13 -0
- package/src/core/adapters/oauth-client-adapter.js +1 -0
- package/src/core/adapters/oauth-client-management-adapter.d.ts +23 -0
- package/src/core/adapters/oauth-client-management-adapter.js +1 -0
- package/src/core/adapters/oauth-grant-type.d.ts +1 -0
- package/src/core/adapters/oauth-grant-type.js +1 -0
- package/src/core/adapters/oauth-policy.d.ts +9 -0
- package/src/core/adapters/oauth-policy.js +1 -0
- package/src/core/adapters/observability-hooks.d.ts +31 -0
- package/src/core/adapters/observability-hooks.js +1 -0
- package/src/core/adapters/pending-auth-request-adapter.d.ts +18 -0
- package/src/core/adapters/pending-auth-request-adapter.js +1 -0
- package/src/core/adapters/refresh-token-adapter.d.ts +24 -0
- package/src/core/adapters/refresh-token-adapter.js +1 -0
- package/src/core/adapters/session-adapter.d.ts +14 -0
- package/src/core/adapters/session-adapter.js +1 -0
- package/src/core/adapters/token-adapter.d.ts +15 -0
- package/src/core/adapters/token-adapter.js +1 -0
- package/src/core/http/bearer-challenge.d.ts +6 -0
- package/src/core/http/bearer-challenge.js +16 -0
- package/src/core/ids/id-codec.d.ts +6 -0
- package/src/core/ids/id-codec.js +30 -0
- package/src/core/index.d.ts +9 -0
- package/src/core/index.js +7 -0
- package/src/core/oauth/pkce.d.ts +9 -0
- package/src/core/oauth/pkce.js +30 -0
- package/src/core/services/access-token-service.d.ts +42 -0
- package/src/core/services/access-token-service.js +304 -0
- package/src/core/services/auth-error.d.ts +14 -0
- package/src/core/services/auth-error.js +47 -0
- package/src/core/services/contracts.d.ts +23 -0
- package/src/core/services/contracts.js +1 -0
- package/src/core/services/direct-auth-service.d.ts +50 -0
- package/src/core/services/direct-auth-service.js +267 -0
- package/src/core/services/index.d.ts +7 -0
- package/src/core/services/index.js +5 -0
- package/src/core/services/mcp-auth-service.d.ts +39 -0
- package/src/core/services/mcp-auth-service.js +170 -0
- package/src/core/services/oauth-service.d.ts +91 -0
- package/src/core/services/oauth-service.js +571 -0
- package/src/core/services/observability.d.ts +22 -0
- package/src/core/services/observability.js +71 -0
- package/src/core/services/revocation-policy.d.ts +21 -0
- package/src/core/services/revocation-policy.js +51 -0
- package/src/core/sessions/client-session.d.ts +7 -0
- package/src/core/sessions/client-session.js +18 -0
- package/src/core/tokens/access-claims.d.ts +21 -0
- package/src/core/tokens/access-claims.js +128 -0
- package/src/core/tokens/id-claims.d.ts +20 -0
- package/src/core/tokens/id-claims.js +25 -0
- package/src/core/types/auth-contract.d.ts +33 -0
- package/src/core/types/auth-contract.js +1 -0
- package/src/express/index.d.ts +1 -0
- package/src/express/index.js +1 -0
- package/src/express/protected-route.d.ts +44 -0
- package/src/express/protected-route.js +119 -0
- package/src/index.d.ts +8 -0
- package/src/index.js +8 -0
- package/src/mcp/index.d.ts +1 -0
- package/src/mcp/index.js +1 -0
- package/src/mcp/json-rpc-auth.d.ts +5 -0
- package/src/mcp/json-rpc-auth.js +41 -0
- package/src/next/app/catch-all.d.ts +32 -0
- package/src/next/app/catch-all.js +82 -0
- package/src/next/app/cookies.d.ts +22 -0
- package/src/next/app/cookies.js +36 -0
- package/src/next/app/direct-auth-handlers.d.ts +55 -0
- package/src/next/app/direct-auth-handlers.js +419 -0
- package/src/next/app/index.d.ts +8 -0
- package/src/next/app/index.js +8 -0
- package/src/next/app/mcp-oauth-handlers.d.ts +74 -0
- package/src/next/app/mcp-oauth-handlers.js +365 -0
- package/src/next/app/protected-route.d.ts +27 -0
- package/src/next/app/protected-route.js +59 -0
- package/src/next/app/request.d.ts +12 -0
- package/src/next/app/request.js +30 -0
- package/src/next/app/response.d.ts +16 -0
- package/src/next/app/response.js +48 -0
- package/src/next/app/wrapper.d.ts +28 -0
- package/src/next/app/wrapper.js +78 -0
- package/src/next/index.d.ts +6 -0
- package/src/next/index.js +5 -0
- package/src/next/pages/catch-all.d.ts +19 -0
- package/src/next/pages/catch-all.js +60 -0
- package/src/next/pages/cookies.d.ts +41 -0
- package/src/next/pages/cookies.js +87 -0
- package/src/next/pages/direct-auth-handlers.d.ts +58 -0
- package/src/next/pages/direct-auth-handlers.js +425 -0
- package/src/next/pages/index.d.ts +8 -0
- package/src/next/pages/index.js +8 -0
- package/src/next/pages/mcp-oauth-handlers.d.ts +77 -0
- package/src/next/pages/mcp-oauth-handlers.js +341 -0
- package/src/next/pages/protected-route.d.ts +28 -0
- package/src/next/pages/protected-route.js +59 -0
- package/src/next/pages/request.d.ts +14 -0
- package/src/next/pages/request.js +66 -0
- package/src/next/pages/response.d.ts +28 -0
- package/src/next/pages/response.js +29 -0
- package/src/next/pages/wrapper.d.ts +29 -0
- package/src/next/pages/wrapper.js +74 -0
- package/src/next/rewrites.d.ts +12 -0
- package/src/next/rewrites.js +74 -0
- package/src/next/shared/auth-http.d.ts +24 -0
- package/src/next/shared/auth-http.js +42 -0
- package/src/next/shared/auth-routes.d.ts +17 -0
- package/src/next/shared/auth-routes.js +153 -0
- package/src/next/shared/direct-auth-utils.d.ts +71 -0
- package/src/next/shared/direct-auth-utils.js +275 -0
- package/src/next/shared/oauth-utils.d.ts +45 -0
- package/src/next/shared/oauth-utils.js +308 -0
- package/src/next/shared/well-known-utils.d.ts +46 -0
- package/src/next/shared/well-known-utils.js +108 -0
- package/src/testing/in-memory/in-memory-access-token-revocation-adapter.d.ts +2 -0
- package/src/testing/in-memory/in-memory-access-token-revocation-adapter.js +14 -0
- package/src/testing/in-memory/in-memory-authorization-code-adapter.d.ts +2 -0
- package/src/testing/in-memory/in-memory-authorization-code-adapter.js +36 -0
- package/src/testing/in-memory/in-memory-oauth-client-adapter.d.ts +14 -0
- package/src/testing/in-memory/in-memory-oauth-client-adapter.js +26 -0
- package/src/testing/in-memory/in-memory-pending-auth-request-adapter.d.ts +2 -0
- package/src/testing/in-memory/in-memory-pending-auth-request-adapter.js +43 -0
- package/src/testing/in-memory/in-memory-refresh-token-adapter.d.ts +2 -0
- package/src/testing/in-memory/in-memory-refresh-token-adapter.js +67 -0
- package/src/testing/in-memory/in-memory-session-adapter.d.ts +6 -0
- package/src/testing/in-memory/in-memory-session-adapter.js +43 -0
- package/src/testing/in-memory/index.d.ts +7 -0
- package/src/testing/in-memory/index.js +7 -0
- package/src/testing/in-memory/test-fixtures.d.ts +5 -0
- package/src/testing/in-memory/test-fixtures.js +18 -0
- package/src/testing/index.d.ts +2 -0
- package/src/testing/index.js +4 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { OAuthGrantType } from '../../core/adapters/oauth-grant-type';
|
|
2
|
+
import type { McpAuthService, McpAuthenticationResult, OAuthService } from '../../core/services/index';
|
|
3
|
+
import type { AuthActor } from '../../core/types/auth-contract';
|
|
4
|
+
export type CreateAppMcpHandlerOptions<TSessionId, TUserId, TActor extends AuthActor = AuthActor, TServerSessionData extends Record<string, unknown> = Record<string, never>, TClientSessionData extends Record<string, unknown> = Record<string, never>, TExtClaims extends Record<string, unknown> = Record<string, never>> = {
|
|
5
|
+
mcpAuthService: McpAuthService<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims>;
|
|
6
|
+
handleRequest: (input: {
|
|
7
|
+
req: Request;
|
|
8
|
+
body: unknown;
|
|
9
|
+
authentication: McpAuthenticationResult<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims>;
|
|
10
|
+
requestId?: string;
|
|
11
|
+
}) => Promise<unknown | Response | void> | unknown | Response | void;
|
|
12
|
+
parseBody?: (req: Request) => Promise<unknown> | unknown;
|
|
13
|
+
expectedAudience?: string;
|
|
14
|
+
allowedActors?: readonly TActor[] | ReadonlySet<TActor>;
|
|
15
|
+
challengeScope?: string;
|
|
16
|
+
resourceMetadataUrl?: string;
|
|
17
|
+
requestIdHeaderName?: string;
|
|
18
|
+
authorizationHeaderName?: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function createAppMcpHandler<TSessionId, TUserId, TActor extends AuthActor = AuthActor, TServerSessionData extends Record<string, unknown> = Record<string, never>, TClientSessionData extends Record<string, unknown> = Record<string, never>, TExtClaims extends Record<string, unknown> = Record<string, never>>(options: CreateAppMcpHandlerOptions<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims>): (req: Request) => Promise<Response>;
|
|
21
|
+
export type CreateAppOAuthHandlersOptions<TUserId, TActor extends AuthActor = AuthActor, TExtClaims extends Record<string, unknown> = Record<string, never>> = {
|
|
22
|
+
oauthService: OAuthService<TUserId, TActor, TExtClaims>;
|
|
23
|
+
resolveUserId: (input: {
|
|
24
|
+
req: Request;
|
|
25
|
+
requestId: string;
|
|
26
|
+
approved: boolean;
|
|
27
|
+
}) => Promise<TUserId | null> | TUserId | null;
|
|
28
|
+
requiredScope?: string;
|
|
29
|
+
requireState?: boolean;
|
|
30
|
+
defaultCodeMethod?: 'S256' | 'plain';
|
|
31
|
+
generateRequestId?: () => string;
|
|
32
|
+
getAuthorizeLoginLocation?: (input: {
|
|
33
|
+
req: Request;
|
|
34
|
+
requestId: string;
|
|
35
|
+
expiresAtUnix: number;
|
|
36
|
+
}) => string;
|
|
37
|
+
token?: {
|
|
38
|
+
authorizationCodeSessionTtlSeconds?: number;
|
|
39
|
+
issueRefreshToken?: boolean;
|
|
40
|
+
allowGrantTypeInference?: boolean;
|
|
41
|
+
clientCredentials?: {
|
|
42
|
+
enabled?: boolean;
|
|
43
|
+
sessionTtlSeconds?: number;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
requestIdHeaderName?: string;
|
|
47
|
+
authorizationHeaderName?: string;
|
|
48
|
+
};
|
|
49
|
+
export type AppOAuthHandlers = {
|
|
50
|
+
authorize: (req: Request) => Promise<Response>;
|
|
51
|
+
authorizeConfirm: (req: Request) => Promise<Response>;
|
|
52
|
+
token: (req: Request) => Promise<Response>;
|
|
53
|
+
};
|
|
54
|
+
export declare function createAppOAuthHandlers<TUserId, TActor extends AuthActor = AuthActor, TExtClaims extends Record<string, unknown> = Record<string, never>>(options: CreateAppOAuthHandlersOptions<TUserId, TActor, TExtClaims>): AppOAuthHandlers;
|
|
55
|
+
export type CreateAppWellKnownHandlersOptions = {
|
|
56
|
+
issuer?: string | ((req: Request) => string);
|
|
57
|
+
authorizationEndpoint?: string;
|
|
58
|
+
tokenEndpoint?: string;
|
|
59
|
+
protectedResource?: string | ((req: Request) => string);
|
|
60
|
+
authorizationServers?: ReadonlyArray<string> | ((req: Request) => ReadonlyArray<string>);
|
|
61
|
+
responseTypesSupported?: readonly string[];
|
|
62
|
+
grantTypesSupported?: readonly OAuthGrantType[];
|
|
63
|
+
codeChallengeMethodsSupported?: ReadonlyArray<'S256' | 'plain'>;
|
|
64
|
+
tokenEndpointAuthMethodsSupported?: readonly string[];
|
|
65
|
+
scopesSupported?: readonly string[];
|
|
66
|
+
cacheControlHeader?: string;
|
|
67
|
+
fallbackOrigin?: string;
|
|
68
|
+
};
|
|
69
|
+
export type AppWellKnownHandlers = {
|
|
70
|
+
oauthProtectedResource: (req: Request) => Promise<Response> | Response;
|
|
71
|
+
oauthAuthorizationServer: (req: Request) => Promise<Response> | Response;
|
|
72
|
+
openidConfiguration: (req: Request) => Promise<Response> | Response;
|
|
73
|
+
};
|
|
74
|
+
export declare function createAppWellKnownHandlers(options?: CreateAppWellKnownHandlersOptions): AppWellKnownHandlers;
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { AuthServiceError } from '../../core/services/auth-error';
|
|
3
|
+
import { sendAppRedirect } from './response';
|
|
4
|
+
import { withAppAuthRoute } from './wrapper';
|
|
5
|
+
import { appendUrlParams, parseAuthorizeRequest, parseBodyToRecord, parseBoolean, parseOAuthTokenRequest, parsePositiveSafeInteger, } from '../shared/oauth-utils';
|
|
6
|
+
import { buildWellKnownMetadata, resolveRequestOrigin, } from '../shared/well-known-utils';
|
|
7
|
+
function jsonResponse(statusCode, body, headers) {
|
|
8
|
+
const responseHeaders = new Headers(headers);
|
|
9
|
+
responseHeaders.set('Content-Type', 'application/json');
|
|
10
|
+
return new Response(JSON.stringify(body), {
|
|
11
|
+
status: statusCode,
|
|
12
|
+
headers: responseHeaders,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function methodNotAllowedResponse(allowedMethods) {
|
|
16
|
+
return jsonResponse(405, {
|
|
17
|
+
error: 'method_not_allowed',
|
|
18
|
+
error_description: 'HTTP method not allowed for auth route.',
|
|
19
|
+
}, { Allow: allowedMethods.join(', ') });
|
|
20
|
+
}
|
|
21
|
+
async function readBodyAsRecord(req) {
|
|
22
|
+
return parseBodyToRecord(await req.text());
|
|
23
|
+
}
|
|
24
|
+
async function defaultReadMcpBody(req) {
|
|
25
|
+
if (req.method !== 'POST') {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const raw = await req.text();
|
|
29
|
+
const trimmed = raw.trim();
|
|
30
|
+
if (trimmed.length === 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(trimmed);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw new AuthServiceError({
|
|
38
|
+
code: 'invalid_request',
|
|
39
|
+
message: 'MCP request body must be valid JSON.',
|
|
40
|
+
cause: error,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function getAppOrigin(req, fallbackOrigin) {
|
|
45
|
+
const hostHeader = req.headers.get('host');
|
|
46
|
+
const forwardedHostHeader = req.headers.get('x-forwarded-host');
|
|
47
|
+
const forwardedProtoHeader = req.headers.get('x-forwarded-proto');
|
|
48
|
+
return resolveRequestOrigin({
|
|
49
|
+
requestUrl: req.url,
|
|
50
|
+
...(hostHeader === null ? {} : { hostHeader }),
|
|
51
|
+
...(forwardedHostHeader === null ? {} : { forwardedHostHeader }),
|
|
52
|
+
...(forwardedProtoHeader === null ? {} : { forwardedProtoHeader }),
|
|
53
|
+
...(fallbackOrigin === undefined ? {} : { fallbackOrigin }),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function resolveMetadata(req, options) {
|
|
57
|
+
const issuerValue = typeof options.issuer === 'function' ? options.issuer(req) : options.issuer;
|
|
58
|
+
const issuer = issuerValue ?? getAppOrigin(req, options.fallbackOrigin);
|
|
59
|
+
const protectedResourceValue = typeof options.protectedResource === 'function'
|
|
60
|
+
? options.protectedResource(req)
|
|
61
|
+
: options.protectedResource;
|
|
62
|
+
const authorizationServersValue = typeof options.authorizationServers === 'function'
|
|
63
|
+
? options.authorizationServers(req)
|
|
64
|
+
: options.authorizationServers;
|
|
65
|
+
return buildWellKnownMetadata({
|
|
66
|
+
issuer,
|
|
67
|
+
...(options.authorizationEndpoint === undefined
|
|
68
|
+
? {}
|
|
69
|
+
: { authorizationEndpoint: options.authorizationEndpoint }),
|
|
70
|
+
...(options.tokenEndpoint === undefined
|
|
71
|
+
? {}
|
|
72
|
+
: { tokenEndpoint: options.tokenEndpoint }),
|
|
73
|
+
...(protectedResourceValue === undefined
|
|
74
|
+
? {}
|
|
75
|
+
: { protectedResource: protectedResourceValue }),
|
|
76
|
+
...(authorizationServersValue === undefined
|
|
77
|
+
? {}
|
|
78
|
+
: { authorizationServers: authorizationServersValue }),
|
|
79
|
+
...(options.responseTypesSupported === undefined
|
|
80
|
+
? {}
|
|
81
|
+
: { responseTypesSupported: options.responseTypesSupported }),
|
|
82
|
+
...(options.grantTypesSupported === undefined
|
|
83
|
+
? {}
|
|
84
|
+
: { grantTypesSupported: options.grantTypesSupported }),
|
|
85
|
+
...(options.codeChallengeMethodsSupported === undefined
|
|
86
|
+
? {}
|
|
87
|
+
: {
|
|
88
|
+
codeChallengeMethodsSupported: options.codeChallengeMethodsSupported,
|
|
89
|
+
}),
|
|
90
|
+
...(options.tokenEndpointAuthMethodsSupported === undefined
|
|
91
|
+
? {}
|
|
92
|
+
: {
|
|
93
|
+
tokenEndpointAuthMethodsSupported: options.tokenEndpointAuthMethodsSupported,
|
|
94
|
+
}),
|
|
95
|
+
...(options.scopesSupported === undefined
|
|
96
|
+
? {}
|
|
97
|
+
: { scopesSupported: options.scopesSupported }),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function buildTokenOutput(input) {
|
|
101
|
+
const expiresIn = Math.max(0, input.accessClaims.exp - input.accessClaims.iat);
|
|
102
|
+
return {
|
|
103
|
+
access_token: input.accessToken,
|
|
104
|
+
token_type: 'Bearer',
|
|
105
|
+
expires_in: expiresIn,
|
|
106
|
+
...(input.refreshToken === undefined
|
|
107
|
+
? {}
|
|
108
|
+
: { refresh_token: input.refreshToken }),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export function createAppMcpHandler(options) {
|
|
112
|
+
return withAppAuthRoute({
|
|
113
|
+
...(options.requestIdHeaderName === undefined
|
|
114
|
+
? {}
|
|
115
|
+
: { requestIdHeaderName: options.requestIdHeaderName }),
|
|
116
|
+
...(options.authorizationHeaderName === undefined
|
|
117
|
+
? {}
|
|
118
|
+
: { authorizationHeaderName: options.authorizationHeaderName }),
|
|
119
|
+
challenge: {
|
|
120
|
+
...(options.challengeScope === undefined
|
|
121
|
+
? {}
|
|
122
|
+
: { scope: options.challengeScope }),
|
|
123
|
+
...(options.resourceMetadataUrl === undefined
|
|
124
|
+
? {}
|
|
125
|
+
: { resourceMetadataUrl: options.resourceMetadataUrl }),
|
|
126
|
+
},
|
|
127
|
+
handler: async ({ req, requestId, transport }) => {
|
|
128
|
+
const body = options.parseBody
|
|
129
|
+
? await options.parseBody(req)
|
|
130
|
+
: await defaultReadMcpBody(req);
|
|
131
|
+
const authentication = await options.mcpAuthService.authenticateRequest({
|
|
132
|
+
body,
|
|
133
|
+
transport,
|
|
134
|
+
...(requestId === undefined ? {} : { requestId }),
|
|
135
|
+
...(options.expectedAudience === undefined
|
|
136
|
+
? {}
|
|
137
|
+
: { expectedAudience: options.expectedAudience }),
|
|
138
|
+
...(options.allowedActors === undefined
|
|
139
|
+
? {}
|
|
140
|
+
: { allowedActors: options.allowedActors }),
|
|
141
|
+
});
|
|
142
|
+
return options.handleRequest({
|
|
143
|
+
req,
|
|
144
|
+
body,
|
|
145
|
+
authentication,
|
|
146
|
+
...(requestId === undefined ? {} : { requestId }),
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
export function createAppOAuthHandlers(options) {
|
|
152
|
+
const requiredScope = options.requiredScope ?? 'mcp:access';
|
|
153
|
+
const generateRequestId = options.generateRequestId ?? (() => randomUUID());
|
|
154
|
+
const authorizationCodeSessionTtlSeconds = parsePositiveSafeInteger(options.token?.authorizationCodeSessionTtlSeconds ?? 3600, 'authorizationCodeSessionTtlSeconds');
|
|
155
|
+
const clientCredentialsSessionTtlSeconds = parsePositiveSafeInteger(options.token?.clientCredentials?.sessionTtlSeconds ?? 3600, 'clientCredentials.sessionTtlSeconds');
|
|
156
|
+
const getAuthorizeLoginLocation = options.getAuthorizeLoginLocation ??
|
|
157
|
+
(({ requestId }) => `/login?request_id=${requestId}`);
|
|
158
|
+
const authorize = withAppAuthRoute({
|
|
159
|
+
...(options.requestIdHeaderName === undefined
|
|
160
|
+
? {}
|
|
161
|
+
: { requestIdHeaderName: options.requestIdHeaderName }),
|
|
162
|
+
handler: async ({ req, requestId }) => {
|
|
163
|
+
if (req.method !== 'GET') {
|
|
164
|
+
return methodNotAllowedResponse(['GET']);
|
|
165
|
+
}
|
|
166
|
+
const query = Object.fromEntries(new URL(req.url).searchParams.entries());
|
|
167
|
+
const parsed = parseAuthorizeRequest({
|
|
168
|
+
query,
|
|
169
|
+
requiredScope,
|
|
170
|
+
...(options.defaultCodeMethod === undefined
|
|
171
|
+
? {}
|
|
172
|
+
: { defaultCodeMethod: options.defaultCodeMethod }),
|
|
173
|
+
...(options.requireState === undefined
|
|
174
|
+
? {}
|
|
175
|
+
: { requireState: options.requireState }),
|
|
176
|
+
});
|
|
177
|
+
const oauthRequestId = generateRequestId();
|
|
178
|
+
const started = await options.oauthService.startAuthorization({
|
|
179
|
+
requestId: oauthRequestId,
|
|
180
|
+
clientId: parsed.clientId,
|
|
181
|
+
redirectUri: parsed.redirectUri,
|
|
182
|
+
codeChallenge: parsed.codeChallenge,
|
|
183
|
+
codeMethod: parsed.codeMethod,
|
|
184
|
+
scopes: parsed.scopes,
|
|
185
|
+
...(parsed.state === undefined ? {} : { state: parsed.state }),
|
|
186
|
+
...(requestId === undefined ? {} : { auditRequestId: requestId }),
|
|
187
|
+
});
|
|
188
|
+
return {
|
|
189
|
+
location: getAuthorizeLoginLocation({
|
|
190
|
+
req,
|
|
191
|
+
requestId: oauthRequestId,
|
|
192
|
+
expiresAtUnix: started.expiresAtUnix,
|
|
193
|
+
}),
|
|
194
|
+
statusCode: 302,
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
send: ({ output }) => sendAppRedirect(output),
|
|
198
|
+
});
|
|
199
|
+
const authorizeConfirm = withAppAuthRoute({
|
|
200
|
+
...(options.requestIdHeaderName === undefined
|
|
201
|
+
? {}
|
|
202
|
+
: { requestIdHeaderName: options.requestIdHeaderName }),
|
|
203
|
+
handler: async ({ req, requestId }) => {
|
|
204
|
+
if (req.method !== 'POST') {
|
|
205
|
+
return methodNotAllowedResponse(['POST']);
|
|
206
|
+
}
|
|
207
|
+
const body = await readBodyAsRecord(req);
|
|
208
|
+
const query = new URL(req.url).searchParams;
|
|
209
|
+
const pendingRequestId = (typeof body.request_id === 'string' ? body.request_id : undefined) ??
|
|
210
|
+
query.get('request_id') ??
|
|
211
|
+
undefined;
|
|
212
|
+
if (!pendingRequestId) {
|
|
213
|
+
throw new AuthServiceError({
|
|
214
|
+
code: 'invalid_request',
|
|
215
|
+
message: 'Missing required field "request_id".',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const approved = parseBoolean(body.approved, true);
|
|
219
|
+
const userId = await options.resolveUserId({
|
|
220
|
+
req,
|
|
221
|
+
requestId: pendingRequestId,
|
|
222
|
+
approved,
|
|
223
|
+
});
|
|
224
|
+
if (userId === null) {
|
|
225
|
+
throw new AuthServiceError({
|
|
226
|
+
code: 'unauthorized',
|
|
227
|
+
message: 'Authenticated user is required to confirm authorization.',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
const confirmed = await options.oauthService.confirmAuthorization({
|
|
231
|
+
requestId: pendingRequestId,
|
|
232
|
+
userId,
|
|
233
|
+
approved,
|
|
234
|
+
...(requestId === undefined ? {} : { auditRequestId: requestId }),
|
|
235
|
+
});
|
|
236
|
+
const location = confirmed.approved
|
|
237
|
+
? appendUrlParams(confirmed.redirectUri, {
|
|
238
|
+
code: confirmed.authorizationCode,
|
|
239
|
+
state: confirmed.state,
|
|
240
|
+
})
|
|
241
|
+
: appendUrlParams(confirmed.redirectUri, {
|
|
242
|
+
error: 'access_denied',
|
|
243
|
+
state: confirmed.state,
|
|
244
|
+
});
|
|
245
|
+
return {
|
|
246
|
+
location,
|
|
247
|
+
statusCode: 302,
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
send: ({ output }) => sendAppRedirect(output),
|
|
251
|
+
});
|
|
252
|
+
const token = withAppAuthRoute({
|
|
253
|
+
...(options.requestIdHeaderName === undefined
|
|
254
|
+
? {}
|
|
255
|
+
: { requestIdHeaderName: options.requestIdHeaderName }),
|
|
256
|
+
...(options.authorizationHeaderName === undefined
|
|
257
|
+
? {}
|
|
258
|
+
: { authorizationHeaderName: options.authorizationHeaderName }),
|
|
259
|
+
handler: async ({ req, requestId }) => {
|
|
260
|
+
if (req.method !== 'POST') {
|
|
261
|
+
return methodNotAllowedResponse(['POST']);
|
|
262
|
+
}
|
|
263
|
+
const body = await readBodyAsRecord(req);
|
|
264
|
+
const authorizationHeader = req.headers.get(options.authorizationHeaderName ?? 'authorization');
|
|
265
|
+
const parsed = parseOAuthTokenRequest({
|
|
266
|
+
body,
|
|
267
|
+
...(authorizationHeader === null ? {} : { authorizationHeader }),
|
|
268
|
+
...(options.token?.clientCredentials?.enabled === undefined
|
|
269
|
+
? {}
|
|
270
|
+
: {
|
|
271
|
+
allowClientCredentials: options.token.clientCredentials.enabled,
|
|
272
|
+
}),
|
|
273
|
+
...(options.token?.allowGrantTypeInference === undefined
|
|
274
|
+
? {}
|
|
275
|
+
: {
|
|
276
|
+
allowGrantTypeInference: options.token.allowGrantTypeInference,
|
|
277
|
+
}),
|
|
278
|
+
});
|
|
279
|
+
if (parsed.grantType === 'authorization_code') {
|
|
280
|
+
const exchanged = await options.oauthService.exchangeAuthorizationCode({
|
|
281
|
+
clientId: parsed.clientId,
|
|
282
|
+
clientSecret: parsed.clientSecret,
|
|
283
|
+
authorizationCode: parsed.authorizationCode,
|
|
284
|
+
redirectUri: parsed.redirectUri,
|
|
285
|
+
codeVerifier: parsed.codeVerifier,
|
|
286
|
+
sessionTtlSeconds: authorizationCodeSessionTtlSeconds,
|
|
287
|
+
...(options.token?.issueRefreshToken === undefined
|
|
288
|
+
? {}
|
|
289
|
+
: { issueRefreshToken: options.token.issueRefreshToken }),
|
|
290
|
+
...(requestId === undefined ? {} : { auditRequestId: requestId }),
|
|
291
|
+
});
|
|
292
|
+
return buildTokenOutput({
|
|
293
|
+
accessToken: exchanged.accessToken,
|
|
294
|
+
accessClaims: exchanged.accessClaims,
|
|
295
|
+
...(exchanged.refreshToken === undefined
|
|
296
|
+
? {}
|
|
297
|
+
: { refreshToken: exchanged.refreshToken }),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
if (parsed.grantType === 'refresh_token') {
|
|
301
|
+
const exchanged = await options.oauthService.exchangeRefreshToken({
|
|
302
|
+
clientId: parsed.clientId,
|
|
303
|
+
clientSecret: parsed.clientSecret,
|
|
304
|
+
refreshToken: parsed.refreshToken,
|
|
305
|
+
...(requestId === undefined ? {} : { auditRequestId: requestId }),
|
|
306
|
+
});
|
|
307
|
+
return buildTokenOutput({
|
|
308
|
+
accessToken: exchanged.accessToken,
|
|
309
|
+
accessClaims: exchanged.accessClaims,
|
|
310
|
+
refreshToken: exchanged.refreshToken,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
const exchanged = await options.oauthService.exchangeClientCredentials({
|
|
314
|
+
clientId: parsed.clientId,
|
|
315
|
+
clientSecret: parsed.clientSecret,
|
|
316
|
+
sessionTtlSeconds: clientCredentialsSessionTtlSeconds,
|
|
317
|
+
...(requestId === undefined ? {} : { auditRequestId: requestId }),
|
|
318
|
+
});
|
|
319
|
+
return buildTokenOutput({
|
|
320
|
+
accessToken: exchanged.accessToken,
|
|
321
|
+
accessClaims: exchanged.accessClaims,
|
|
322
|
+
});
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
return {
|
|
326
|
+
authorize,
|
|
327
|
+
authorizeConfirm,
|
|
328
|
+
token,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
export function createAppWellKnownHandlers(options = {}) {
|
|
332
|
+
const cacheControlHeader = options.cacheControlHeader ?? 'no-store';
|
|
333
|
+
const oauthProtectedResource = (req) => {
|
|
334
|
+
if (req.method !== 'GET') {
|
|
335
|
+
return methodNotAllowedResponse(['GET']);
|
|
336
|
+
}
|
|
337
|
+
const metadata = resolveMetadata(req, options);
|
|
338
|
+
return jsonResponse(200, metadata.oauthProtectedResource, {
|
|
339
|
+
'Cache-Control': cacheControlHeader,
|
|
340
|
+
});
|
|
341
|
+
};
|
|
342
|
+
const oauthAuthorizationServer = (req) => {
|
|
343
|
+
if (req.method !== 'GET') {
|
|
344
|
+
return methodNotAllowedResponse(['GET']);
|
|
345
|
+
}
|
|
346
|
+
const metadata = resolveMetadata(req, options);
|
|
347
|
+
return jsonResponse(200, metadata.oauthAuthorizationServer, {
|
|
348
|
+
'Cache-Control': cacheControlHeader,
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
const openidConfiguration = (req) => {
|
|
352
|
+
if (req.method !== 'GET') {
|
|
353
|
+
return methodNotAllowedResponse(['GET']);
|
|
354
|
+
}
|
|
355
|
+
const metadata = resolveMetadata(req, options);
|
|
356
|
+
return jsonResponse(200, metadata.openidConfiguration, {
|
|
357
|
+
'Cache-Control': cacheControlHeader,
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
return {
|
|
361
|
+
oauthProtectedResource,
|
|
362
|
+
oauthAuthorizationServer,
|
|
363
|
+
openidConfiguration,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AccessTokenSource } from '../../core/adapters/access-token-transport-adapter';
|
|
2
|
+
import type { ValidatedAccessTokenResult } from '../../core/services/contracts';
|
|
3
|
+
import type { DirectAuthService } from '../../core/services/direct-auth-service';
|
|
4
|
+
import type { AuthActor } from '../../core/types/auth-contract';
|
|
5
|
+
import { type DirectAccessTokenTransportConfig } from '../shared/direct-auth-utils';
|
|
6
|
+
import { type WithAppAuthRouteOptions } from './wrapper';
|
|
7
|
+
export type AppProtectedAuth<TSessionId, TUserId, TActor extends AuthActor = AuthActor, TServerSessionData extends Record<string, unknown> = Record<string, never>, TClientSessionData extends Record<string, unknown> = Record<string, never>, TExtClaims extends Record<string, unknown> = Record<string, never>> = ValidatedAccessTokenResult<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims> & {
|
|
8
|
+
accessToken: string;
|
|
9
|
+
accessTokenSource: AccessTokenSource | undefined;
|
|
10
|
+
};
|
|
11
|
+
export type AppProtectedRouteContext<TSessionId, TUserId, TActor extends AuthActor = AuthActor, TServerSessionData extends Record<string, unknown> = Record<string, never>, TClientSessionData extends Record<string, unknown> = Record<string, never>, TExtClaims extends Record<string, unknown> = Record<string, never>> = {
|
|
12
|
+
req: Request;
|
|
13
|
+
requestId: string | undefined;
|
|
14
|
+
cookies: Record<string, string | undefined>;
|
|
15
|
+
auth: AppProtectedAuth<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims>;
|
|
16
|
+
};
|
|
17
|
+
export type WithAppProtectedRouteOptions<TSessionId, TUserId, TActor extends AuthActor = AuthActor, TServerSessionData extends Record<string, unknown> = Record<string, never>, TClientSessionData extends Record<string, unknown> = Record<string, never>, TExtClaims extends Record<string, unknown> = Record<string, never>, TOutput = unknown> = {
|
|
18
|
+
directAuthService: DirectAuthService<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims>;
|
|
19
|
+
handler: (input: AppProtectedRouteContext<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims>) => Promise<TOutput | Response | void> | TOutput | Response | void;
|
|
20
|
+
expectedAudience?: string;
|
|
21
|
+
allowedActors?: readonly TActor[] | ReadonlySet<TActor>;
|
|
22
|
+
accessTokenTransport?: DirectAccessTokenTransportConfig<TActor>;
|
|
23
|
+
requestIdHeaderName?: string;
|
|
24
|
+
authorizationHeaderName?: string;
|
|
25
|
+
challenge?: WithAppAuthRouteOptions<TOutput>['challenge'];
|
|
26
|
+
};
|
|
27
|
+
export declare function withAppProtectedRoute<TSessionId, TUserId, TActor extends AuthActor = AuthActor, TServerSessionData extends Record<string, unknown> = Record<string, never>, TClientSessionData extends Record<string, unknown> = Record<string, never>, TExtClaims extends Record<string, unknown> = Record<string, never>, TOutput = unknown>(options: WithAppProtectedRouteOptions<TSessionId, TUserId, TActor, TServerSessionData, TClientSessionData, TExtClaims, TOutput>): (req: Request) => Promise<Response>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { AuthServiceError } from '../../core/services/auth-error';
|
|
2
|
+
import { assertBearerOnlyActorPolicy, resolveAccessTokenTransportAdapter, } from '../shared/direct-auth-utils';
|
|
3
|
+
import { withAppAuthRoute } from './wrapper';
|
|
4
|
+
export function withAppProtectedRoute(options) {
|
|
5
|
+
const accessTokenTransportAdapter = resolveAccessTokenTransportAdapter(options.accessTokenTransport);
|
|
6
|
+
return withAppAuthRoute({
|
|
7
|
+
...(options.challenge === undefined
|
|
8
|
+
? {}
|
|
9
|
+
: { challenge: options.challenge }),
|
|
10
|
+
...(options.requestIdHeaderName === undefined
|
|
11
|
+
? {}
|
|
12
|
+
: { requestIdHeaderName: options.requestIdHeaderName }),
|
|
13
|
+
...(options.authorizationHeaderName === undefined
|
|
14
|
+
? {}
|
|
15
|
+
: { authorizationHeaderName: options.authorizationHeaderName }),
|
|
16
|
+
handler: async ({ req, requestId, transport, cookies }) => {
|
|
17
|
+
const extractedAccessToken = accessTokenTransportAdapter.extractAccessToken({
|
|
18
|
+
transport,
|
|
19
|
+
});
|
|
20
|
+
if (!extractedAccessToken.token) {
|
|
21
|
+
throw new AuthServiceError({
|
|
22
|
+
code: 'invalid_token',
|
|
23
|
+
message: 'Access token is required.',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const validatedAccessToken = await options.directAuthService.validateAccessToken({
|
|
27
|
+
accessToken: extractedAccessToken.token,
|
|
28
|
+
...(requestId === undefined ? {} : { requestId }),
|
|
29
|
+
...(options.expectedAudience === undefined
|
|
30
|
+
? {}
|
|
31
|
+
: { expectedAudience: options.expectedAudience }),
|
|
32
|
+
...(options.allowedActors === undefined
|
|
33
|
+
? {}
|
|
34
|
+
: { allowedActors: options.allowedActors }),
|
|
35
|
+
});
|
|
36
|
+
assertBearerOnlyActorPolicy({
|
|
37
|
+
actor: validatedAccessToken.claims.actor,
|
|
38
|
+
...(extractedAccessToken.source === undefined
|
|
39
|
+
? {}
|
|
40
|
+
: { source: extractedAccessToken.source }),
|
|
41
|
+
...(options.accessTokenTransport?.requireBearerForActors === undefined
|
|
42
|
+
? {}
|
|
43
|
+
: {
|
|
44
|
+
requireBearerForActors: options.accessTokenTransport.requireBearerForActors,
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
return options.handler({
|
|
48
|
+
req,
|
|
49
|
+
requestId,
|
|
50
|
+
cookies,
|
|
51
|
+
auth: {
|
|
52
|
+
...validatedAccessToken,
|
|
53
|
+
accessToken: extractedAccessToken.token,
|
|
54
|
+
accessTokenSource: extractedAccessToken.source,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AccessTokenTransportInput } from '../../core/adapters/access-token-transport-adapter';
|
|
2
|
+
type RequestLike = {
|
|
3
|
+
headers: Headers;
|
|
4
|
+
};
|
|
5
|
+
export declare function getAppAuthorizationHeader(req: RequestLike, headerName?: string): string | undefined;
|
|
6
|
+
export declare function getAppRequestId(req: RequestLike, headerName?: string): string | undefined;
|
|
7
|
+
export declare function getAppCookies(req: RequestLike): Record<string, string | undefined>;
|
|
8
|
+
export declare function buildAppAccessTokenTransportInput(input: {
|
|
9
|
+
req: RequestLike;
|
|
10
|
+
authorizationHeaderName?: string;
|
|
11
|
+
}): AccessTokenTransportInput;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { parseCookieHeader } from '../pages/request';
|
|
2
|
+
function getHeaderValue(headers, headerName) {
|
|
3
|
+
const value = headers.get(headerName);
|
|
4
|
+
if (value === null || value.length === 0) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
export function getAppAuthorizationHeader(req, headerName = 'authorization') {
|
|
10
|
+
return getHeaderValue(req.headers, headerName);
|
|
11
|
+
}
|
|
12
|
+
export function getAppRequestId(req, headerName = 'x-request-id') {
|
|
13
|
+
const requestId = getHeaderValue(req.headers, headerName);
|
|
14
|
+
if (!requestId) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const trimmed = requestId.trim();
|
|
18
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
19
|
+
}
|
|
20
|
+
export function getAppCookies(req) {
|
|
21
|
+
return parseCookieHeader(getHeaderValue(req.headers, 'cookie'));
|
|
22
|
+
}
|
|
23
|
+
export function buildAppAccessTokenTransportInput(input) {
|
|
24
|
+
const authorizationHeader = getAppAuthorizationHeader(input.req, input.authorizationHeaderName);
|
|
25
|
+
const cookies = getAppCookies(input.req);
|
|
26
|
+
return {
|
|
27
|
+
...(authorizationHeader === undefined ? {} : { authorizationHeader }),
|
|
28
|
+
...(Object.keys(cookies).length === 0 ? {} : { cookies }),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AuthServiceError } from '../../core/services/auth-error';
|
|
2
|
+
import { type AuthErrorResponseBody } from '../shared/auth-http';
|
|
3
|
+
export type AppAuthErrorResponseBody = AuthErrorResponseBody;
|
|
4
|
+
export declare function sendAppAuthError(error: AuthServiceError, options?: {
|
|
5
|
+
requestId?: string;
|
|
6
|
+
includeChallengeError?: boolean;
|
|
7
|
+
challengeScope?: string;
|
|
8
|
+
resourceMetadataUrl?: string;
|
|
9
|
+
}): Response;
|
|
10
|
+
export declare function sendAppSystemError(options?: {
|
|
11
|
+
requestId?: string;
|
|
12
|
+
}): Response;
|
|
13
|
+
export declare function sendAppRedirect(input: {
|
|
14
|
+
location: string;
|
|
15
|
+
statusCode?: number;
|
|
16
|
+
}): Response;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { buildAuthErrorHttpResponse, buildSystemErrorHttpResponse, } from '../shared/auth-http';
|
|
2
|
+
function createJsonResponse(input) {
|
|
3
|
+
const headers = new Headers(input.headers);
|
|
4
|
+
headers.set('Content-Type', 'application/json');
|
|
5
|
+
return new Response(JSON.stringify(input.body), {
|
|
6
|
+
status: input.statusCode,
|
|
7
|
+
headers,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export function sendAppAuthError(error, options) {
|
|
11
|
+
const mapped = buildAuthErrorHttpResponse({
|
|
12
|
+
error,
|
|
13
|
+
...(options?.requestId === undefined
|
|
14
|
+
? {}
|
|
15
|
+
: { requestId: options.requestId }),
|
|
16
|
+
...(options?.includeChallengeError === undefined
|
|
17
|
+
? {}
|
|
18
|
+
: { includeChallengeError: options.includeChallengeError }),
|
|
19
|
+
...(options?.challengeScope === undefined
|
|
20
|
+
? {}
|
|
21
|
+
: { challengeScope: options.challengeScope }),
|
|
22
|
+
...(options?.resourceMetadataUrl === undefined
|
|
23
|
+
? {}
|
|
24
|
+
: { resourceMetadataUrl: options.resourceMetadataUrl }),
|
|
25
|
+
});
|
|
26
|
+
return createJsonResponse({
|
|
27
|
+
statusCode: mapped.statusCode,
|
|
28
|
+
body: mapped.body,
|
|
29
|
+
...(mapped.challengeHeader === undefined
|
|
30
|
+
? {}
|
|
31
|
+
: { headers: { 'WWW-Authenticate': mapped.challengeHeader } }),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function sendAppSystemError(options) {
|
|
35
|
+
const mapped = buildSystemErrorHttpResponse(options);
|
|
36
|
+
return createJsonResponse({
|
|
37
|
+
statusCode: mapped.statusCode,
|
|
38
|
+
body: mapped.body,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export function sendAppRedirect(input) {
|
|
42
|
+
return new Response(null, {
|
|
43
|
+
status: input.statusCode ?? 302,
|
|
44
|
+
headers: {
|
|
45
|
+
Location: input.location,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AccessTokenTransportInput } from '../../core/adapters/access-token-transport-adapter';
|
|
2
|
+
export type AppAuthRouteContext = {
|
|
3
|
+
req: Request;
|
|
4
|
+
requestId?: string;
|
|
5
|
+
transport: AccessTokenTransportInput;
|
|
6
|
+
cookies: Record<string, string | undefined>;
|
|
7
|
+
};
|
|
8
|
+
export type WithAppAuthRouteOptions<TOutput> = {
|
|
9
|
+
handler: (input: AppAuthRouteContext) => Promise<TOutput | Response | void> | TOutput | Response | void;
|
|
10
|
+
send?: (input: {
|
|
11
|
+
req: Request;
|
|
12
|
+
output: TOutput;
|
|
13
|
+
requestId?: string;
|
|
14
|
+
}) => Promise<Response> | Response;
|
|
15
|
+
requestIdHeaderName?: string;
|
|
16
|
+
authorizationHeaderName?: string;
|
|
17
|
+
challenge?: {
|
|
18
|
+
includeErrorInWwwAuthenticate?: boolean;
|
|
19
|
+
scope?: string;
|
|
20
|
+
resourceMetadataUrl?: string;
|
|
21
|
+
};
|
|
22
|
+
onSystemError?: (input: {
|
|
23
|
+
req: Request;
|
|
24
|
+
error: unknown;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
}) => Promise<Response | void> | Response | void;
|
|
27
|
+
};
|
|
28
|
+
export declare function withAppAuthRoute<TOutput>(options: WithAppAuthRouteOptions<TOutput>): (req: Request) => Promise<Response>;
|