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
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "actor-gate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Schema-agnostic Next.js auth library for direct and MCP authentication flows.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js",
|
|
9
|
+
"./core": "./src/core/index.js",
|
|
10
|
+
"./config": "./src/config/index.js",
|
|
11
|
+
"./express": "./src/express/index.js",
|
|
12
|
+
"./next": "./src/next/index.js",
|
|
13
|
+
"./mcp": "./src/mcp/index.js",
|
|
14
|
+
"./testing": "./src/testing/index.js"
|
|
15
|
+
},
|
|
16
|
+
"main": "./src/index.js",
|
|
17
|
+
"types": "./src/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"src/**/*.js",
|
|
20
|
+
"src/**/*.d.ts"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AuthActor } from '../core/types/auth-contract';
|
|
2
|
+
export type BaseAuthConfigInput<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession> = {
|
|
3
|
+
actors: TActors;
|
|
4
|
+
session: {
|
|
5
|
+
parseClientSession: (input: unknown) => TClientSession;
|
|
6
|
+
isExpired: (session: TClientSession, nowUnix: number) => boolean;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
export type BaseAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession> = {
|
|
10
|
+
kind: 'base';
|
|
11
|
+
actors: TActors;
|
|
12
|
+
actorSet: ReadonlySet<TActors[number]>;
|
|
13
|
+
session: BaseAuthConfigInput<TActors, TClientSession>['session'];
|
|
14
|
+
};
|
|
15
|
+
export declare function defineBaseAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession>(input: BaseAuthConfigInput<TActors, TClientSession>): BaseAuthConfig<TActors, TClientSession>;
|
|
16
|
+
export type InferAuthActor<TConfig> = TConfig extends BaseAuthConfig<infer TActors, unknown> ? TActors[number] : never;
|
|
17
|
+
export type InferClientSession<TConfig> = TConfig extends BaseAuthConfig<readonly [AuthActor, ...AuthActor[]], infer T> ? T : never;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
function assertNonEmptyActor(value) {
|
|
2
|
+
if (value.trim().length === 0) {
|
|
3
|
+
throw new Error('actors cannot contain empty values.');
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
function normalizeActors(actors) {
|
|
7
|
+
if (actors.length === 0) {
|
|
8
|
+
throw new Error('actors must contain at least one actor.');
|
|
9
|
+
}
|
|
10
|
+
const normalized = [];
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
for (const actor of actors) {
|
|
13
|
+
assertNonEmptyActor(actor);
|
|
14
|
+
if (seen.has(actor)) {
|
|
15
|
+
throw new Error(`actors cannot contain duplicates: "${actor}".`);
|
|
16
|
+
}
|
|
17
|
+
seen.add(actor);
|
|
18
|
+
normalized.push(actor);
|
|
19
|
+
}
|
|
20
|
+
if (!seen.has('USER')) {
|
|
21
|
+
throw new Error('actors must include the reserved USER actor.');
|
|
22
|
+
}
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
export function defineBaseAuthConfig(input) {
|
|
26
|
+
const actors = normalizeActors(input.actors);
|
|
27
|
+
return {
|
|
28
|
+
kind: 'base',
|
|
29
|
+
actors: [...actors],
|
|
30
|
+
actorSet: new Set(actors),
|
|
31
|
+
session: input.session,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { defineBaseAuthConfig, type BaseAuthConfig, type BaseAuthConfigInput, type InferAuthActor, type InferClientSession, } from './base-config';
|
|
2
|
+
export { defineNextJsPublicAuthConfig, type NextJsAuthEndpointSet, type NextJsPublicAuthConfig, type NextJsPublicAuthPaths, toSerializableNextJsPublicAuthConfig, type SerializableNextJsPublicAuthConfig, } from './nextjs-public-config';
|
|
3
|
+
export { defineNextJsServerAuthConfig, type DefineNextJsServerAuthConfigInput, type NextJsServerAuthConfig, type NextJsServerCookieConfig, type NextJsServerCsrfConfig, } from './nextjs-server-config';
|
|
4
|
+
export { defineReactAuthConfig, type DefineReactAuthConfigInput, type ReactAuthConfig, } from './react-config';
|
|
5
|
+
export { ReactAuthClient, createReactAuthClient, type AuthClientStorage, type CreateReactAuthClientInput, } from './react-client';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { defineBaseAuthConfig, } from './base-config';
|
|
2
|
+
export { defineNextJsPublicAuthConfig, toSerializableNextJsPublicAuthConfig, } from './nextjs-public-config';
|
|
3
|
+
export { defineNextJsServerAuthConfig, } from './nextjs-server-config';
|
|
4
|
+
export { defineReactAuthConfig, } from './react-config';
|
|
5
|
+
export { ReactAuthClient, createReactAuthClient, } from './react-client';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { AuthActor } from '../core/types/auth-contract';
|
|
2
|
+
import { type AuthRouteAction } from '../next/shared/auth-routes';
|
|
3
|
+
import { type BuildAuthRewritesOptions, type NextRewrite } from '../next/rewrites';
|
|
4
|
+
import type { BaseAuthConfig } from './base-config';
|
|
5
|
+
export type NextJsAuthEndpointSet = {
|
|
6
|
+
refresh: string;
|
|
7
|
+
logout: string;
|
|
8
|
+
loginStart: string;
|
|
9
|
+
loginFinish: string;
|
|
10
|
+
authorize: string;
|
|
11
|
+
authorizeConfirm: string;
|
|
12
|
+
token: string;
|
|
13
|
+
wellKnownOauthProtectedResource: string;
|
|
14
|
+
wellKnownOauthAuthorizationServer: string;
|
|
15
|
+
wellKnownOpenidConfiguration: string;
|
|
16
|
+
mcp: string;
|
|
17
|
+
};
|
|
18
|
+
export type NextJsPublicAuthPaths = {
|
|
19
|
+
authBasePath: string;
|
|
20
|
+
mcpPath: string;
|
|
21
|
+
authorizePath: string;
|
|
22
|
+
tokenPath: string;
|
|
23
|
+
wellKnownBase: string;
|
|
24
|
+
};
|
|
25
|
+
export type NextJsPublicAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession> = {
|
|
26
|
+
kind: 'nextjs_public';
|
|
27
|
+
base: BaseAuthConfig<TActors, TClientSession>;
|
|
28
|
+
paths: NextJsPublicAuthPaths;
|
|
29
|
+
endpoints: {
|
|
30
|
+
internal: NextJsAuthEndpointSet;
|
|
31
|
+
public: NextJsAuthEndpointSet;
|
|
32
|
+
};
|
|
33
|
+
rewrites: readonly NextRewrite[];
|
|
34
|
+
getAuthRoutePath: (action: AuthRouteAction) => string;
|
|
35
|
+
};
|
|
36
|
+
export type SerializableNextJsPublicAuthConfig = {
|
|
37
|
+
kind: 'nextjs_public_serializable';
|
|
38
|
+
paths: NextJsPublicAuthPaths;
|
|
39
|
+
endpoints: {
|
|
40
|
+
internal: NextJsAuthEndpointSet;
|
|
41
|
+
public: NextJsAuthEndpointSet;
|
|
42
|
+
};
|
|
43
|
+
rewrites: readonly NextRewrite[];
|
|
44
|
+
};
|
|
45
|
+
export declare function defineNextJsPublicAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession>(base: BaseAuthConfig<TActors, TClientSession>, options?: BuildAuthRewritesOptions): NextJsPublicAuthConfig<TActors, TClientSession>;
|
|
46
|
+
export declare function toSerializableNextJsPublicAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession>(config: NextJsPublicAuthConfig<TActors, TClientSession>): SerializableNextJsPublicAuthConfig;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { buildAuthRoutePath, } from '../next/shared/auth-routes';
|
|
2
|
+
import { buildAuthRewrites, } from '../next/rewrites';
|
|
3
|
+
function normalizePath(path) {
|
|
4
|
+
const trimmed = path.trim();
|
|
5
|
+
if (trimmed.length === 0) {
|
|
6
|
+
throw new Error('Path must be a non-empty string.');
|
|
7
|
+
}
|
|
8
|
+
const withLeadingSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
9
|
+
if (withLeadingSlash.length === 1) {
|
|
10
|
+
return withLeadingSlash;
|
|
11
|
+
}
|
|
12
|
+
return withLeadingSlash.endsWith('/')
|
|
13
|
+
? withLeadingSlash.slice(0, -1)
|
|
14
|
+
: withLeadingSlash;
|
|
15
|
+
}
|
|
16
|
+
function joinPath(basePath, suffix) {
|
|
17
|
+
const normalizedBase = normalizePath(basePath);
|
|
18
|
+
const cleanedSuffix = suffix.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
19
|
+
if (normalizedBase === '/') {
|
|
20
|
+
return `/${cleanedSuffix}`;
|
|
21
|
+
}
|
|
22
|
+
return `${normalizedBase}/${cleanedSuffix}`;
|
|
23
|
+
}
|
|
24
|
+
function resolvePaths(options) {
|
|
25
|
+
return {
|
|
26
|
+
authBasePath: normalizePath(options?.authBasePath ?? '/api/auth'),
|
|
27
|
+
mcpPath: normalizePath(options?.mcpPath ?? '/api/mcp'),
|
|
28
|
+
authorizePath: normalizePath(options?.authorizePath ?? '/api/authorize'),
|
|
29
|
+
tokenPath: normalizePath(options?.tokenPath ?? '/api/token'),
|
|
30
|
+
wellKnownBase: normalizePath(options?.wellKnownBase ?? '/api/well-known'),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function buildInternalEndpoints(authBasePath) {
|
|
34
|
+
return {
|
|
35
|
+
refresh: buildAuthRoutePath('refresh', { authBasePath }),
|
|
36
|
+
logout: buildAuthRoutePath('logout', { authBasePath }),
|
|
37
|
+
loginStart: buildAuthRoutePath('login_start', { authBasePath }),
|
|
38
|
+
loginFinish: buildAuthRoutePath('login_finish', { authBasePath }),
|
|
39
|
+
authorize: buildAuthRoutePath('authorize', { authBasePath }),
|
|
40
|
+
authorizeConfirm: buildAuthRoutePath('authorize_confirm', { authBasePath }),
|
|
41
|
+
token: buildAuthRoutePath('token', { authBasePath }),
|
|
42
|
+
wellKnownOauthProtectedResource: buildAuthRoutePath('well_known_oauth_protected_resource', { authBasePath }),
|
|
43
|
+
wellKnownOauthAuthorizationServer: buildAuthRoutePath('well_known_oauth_authorization_server', { authBasePath }),
|
|
44
|
+
wellKnownOpenidConfiguration: buildAuthRoutePath('well_known_openid_configuration', { authBasePath }),
|
|
45
|
+
mcp: joinPath(authBasePath, 'mcp'),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function buildPublicEndpoints(paths) {
|
|
49
|
+
return {
|
|
50
|
+
refresh: buildAuthRoutePath('refresh'),
|
|
51
|
+
logout: buildAuthRoutePath('logout'),
|
|
52
|
+
loginStart: buildAuthRoutePath('login_start'),
|
|
53
|
+
loginFinish: buildAuthRoutePath('login_finish'),
|
|
54
|
+
authorize: paths.authorizePath,
|
|
55
|
+
authorizeConfirm: joinPath(paths.authorizePath, 'confirm'),
|
|
56
|
+
token: paths.tokenPath,
|
|
57
|
+
wellKnownOauthProtectedResource: joinPath(paths.wellKnownBase, 'oauth-protected-resource'),
|
|
58
|
+
wellKnownOauthAuthorizationServer: joinPath(paths.wellKnownBase, 'oauth-authorization-server'),
|
|
59
|
+
wellKnownOpenidConfiguration: joinPath(paths.wellKnownBase, 'openid-configuration'),
|
|
60
|
+
mcp: paths.mcpPath,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function defineNextJsPublicAuthConfig(base, options) {
|
|
64
|
+
const paths = resolvePaths(options);
|
|
65
|
+
const rewrites = buildAuthRewrites(paths);
|
|
66
|
+
const internalEndpoints = buildInternalEndpoints(paths.authBasePath);
|
|
67
|
+
return {
|
|
68
|
+
kind: 'nextjs_public',
|
|
69
|
+
base,
|
|
70
|
+
paths,
|
|
71
|
+
endpoints: {
|
|
72
|
+
internal: internalEndpoints,
|
|
73
|
+
public: buildPublicEndpoints(paths),
|
|
74
|
+
},
|
|
75
|
+
rewrites,
|
|
76
|
+
getAuthRoutePath: action => buildAuthRoutePath(action, paths),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export function toSerializableNextJsPublicAuthConfig(config) {
|
|
80
|
+
return {
|
|
81
|
+
kind: 'nextjs_public_serializable',
|
|
82
|
+
paths: { ...config.paths },
|
|
83
|
+
endpoints: {
|
|
84
|
+
internal: { ...config.endpoints.internal },
|
|
85
|
+
public: { ...config.endpoints.public },
|
|
86
|
+
},
|
|
87
|
+
rewrites: config.rewrites.map(rewrite => ({ ...rewrite })),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AuthActor } from '../core/types/auth-contract';
|
|
2
|
+
import type { NextJsPublicAuthConfig } from './nextjs-public-config';
|
|
3
|
+
export type NextJsServerCookieConfig = {
|
|
4
|
+
accessTokenCookieName?: string;
|
|
5
|
+
refreshTokenCookieName?: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
sameSite?: 'lax' | 'strict' | 'none';
|
|
8
|
+
secure?: boolean;
|
|
9
|
+
secureInProduction?: boolean;
|
|
10
|
+
};
|
|
11
|
+
export type NextJsServerCsrfConfig = {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
headerName?: string;
|
|
14
|
+
cookieName?: string;
|
|
15
|
+
bodyFieldName?: string;
|
|
16
|
+
ignorePaths?: readonly string[];
|
|
17
|
+
};
|
|
18
|
+
export type DefineNextJsServerAuthConfigInput<TServices, TAdapters extends Record<string, unknown> = Record<string, never>> = {
|
|
19
|
+
services: TServices;
|
|
20
|
+
adapters?: TAdapters;
|
|
21
|
+
cookies?: NextJsServerCookieConfig;
|
|
22
|
+
csrf?: NextJsServerCsrfConfig;
|
|
23
|
+
};
|
|
24
|
+
export type NextJsServerAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession, TServices, TAdapters extends Record<string, unknown> = Record<string, never>> = {
|
|
25
|
+
kind: 'nextjs_server';
|
|
26
|
+
publicConfig: NextJsPublicAuthConfig<TActors, TClientSession>;
|
|
27
|
+
services: TServices;
|
|
28
|
+
adapters?: TAdapters;
|
|
29
|
+
cookies?: NextJsServerCookieConfig;
|
|
30
|
+
csrf?: NextJsServerCsrfConfig;
|
|
31
|
+
};
|
|
32
|
+
export declare function defineNextJsServerAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession, TServices, TAdapters extends Record<string, unknown> = Record<string, never>>(publicConfig: NextJsPublicAuthConfig<TActors, TClientSession>, input: DefineNextJsServerAuthConfigInput<TServices, TAdapters>): NextJsServerAuthConfig<TActors, TClientSession, TServices, TAdapters>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function defineNextJsServerAuthConfig(publicConfig, input) {
|
|
2
|
+
return {
|
|
3
|
+
kind: 'nextjs_server',
|
|
4
|
+
publicConfig,
|
|
5
|
+
services: input.services,
|
|
6
|
+
...(input.adapters === undefined ? {} : { adapters: input.adapters }),
|
|
7
|
+
...(input.cookies === undefined ? {} : { cookies: input.cookies }),
|
|
8
|
+
...(input.csrf === undefined ? {} : { csrf: input.csrf }),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AuthActor } from '../core/types/auth-contract';
|
|
2
|
+
import type { ReactAuthConfig } from './react-config';
|
|
3
|
+
export type AuthClientStorage = {
|
|
4
|
+
getItem: (key: string) => string | null;
|
|
5
|
+
setItem: (key: string, value: string) => void;
|
|
6
|
+
removeItem: (key: string) => void;
|
|
7
|
+
};
|
|
8
|
+
export type CreateReactAuthClientInput = {
|
|
9
|
+
storage?: AuthClientStorage;
|
|
10
|
+
};
|
|
11
|
+
export declare class ReactAuthClient<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession> {
|
|
12
|
+
private readonly config;
|
|
13
|
+
private readonly storage;
|
|
14
|
+
constructor(config: ReactAuthConfig<TActors, TClientSession>, input?: CreateReactAuthClientInput);
|
|
15
|
+
get sessionStorageKey(): string;
|
|
16
|
+
get endpoints(): ReactAuthConfig<TActors, TClientSession>['endpoints'];
|
|
17
|
+
parseClientSession(input: unknown): TClientSession;
|
|
18
|
+
isSessionExpired(session: TClientSession): boolean;
|
|
19
|
+
readStoredSession(): TClientSession | null;
|
|
20
|
+
writeStoredSession(session: TClientSession | null): void;
|
|
21
|
+
clearStoredSession(): void;
|
|
22
|
+
}
|
|
23
|
+
export declare function createReactAuthClient<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession>(config: ReactAuthConfig<TActors, TClientSession>, input?: CreateReactAuthClientInput): ReactAuthClient<TActors, TClientSession>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export class ReactAuthClient {
|
|
2
|
+
config;
|
|
3
|
+
storage;
|
|
4
|
+
constructor(config, input = {}) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
this.storage = input.storage;
|
|
7
|
+
}
|
|
8
|
+
get sessionStorageKey() {
|
|
9
|
+
return this.config.sessionStorageKey;
|
|
10
|
+
}
|
|
11
|
+
get endpoints() {
|
|
12
|
+
return this.config.endpoints;
|
|
13
|
+
}
|
|
14
|
+
parseClientSession(input) {
|
|
15
|
+
return this.config.parseClientSession(input);
|
|
16
|
+
}
|
|
17
|
+
isSessionExpired(session) {
|
|
18
|
+
return this.config.isSessionExpired(session);
|
|
19
|
+
}
|
|
20
|
+
readStoredSession() {
|
|
21
|
+
if (!this.storage) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const raw = this.storage.getItem(this.config.sessionStorageKey);
|
|
25
|
+
if (!raw) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
this.storage.removeItem(this.config.sessionStorageKey);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
let session;
|
|
37
|
+
try {
|
|
38
|
+
session = this.config.parseClientSession(parsed);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
this.storage.removeItem(this.config.sessionStorageKey);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if (this.config.isSessionExpired(session)) {
|
|
45
|
+
this.storage.removeItem(this.config.sessionStorageKey);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return session;
|
|
49
|
+
}
|
|
50
|
+
writeStoredSession(session) {
|
|
51
|
+
if (!this.storage) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (session === null) {
|
|
55
|
+
this.storage.removeItem(this.config.sessionStorageKey);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.storage.setItem(this.config.sessionStorageKey, JSON.stringify(session));
|
|
59
|
+
}
|
|
60
|
+
clearStoredSession() {
|
|
61
|
+
if (!this.storage) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.storage.removeItem(this.config.sessionStorageKey);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function createReactAuthClient(config, input) {
|
|
68
|
+
return new ReactAuthClient(config, input);
|
|
69
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AuthActor } from '../core/types/auth-contract';
|
|
2
|
+
import type { NextJsAuthEndpointSet, NextJsPublicAuthConfig } from './nextjs-public-config';
|
|
3
|
+
export type DefineReactAuthConfigInput = {
|
|
4
|
+
sessionStorageKey?: string;
|
|
5
|
+
queryKey?: readonly [string, ...string[]];
|
|
6
|
+
nowUnix?: () => number;
|
|
7
|
+
useInternalEndpoints?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type ReactAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession> = {
|
|
10
|
+
kind: 'react';
|
|
11
|
+
publicConfig: NextJsPublicAuthConfig<TActors, TClientSession>;
|
|
12
|
+
sessionStorageKey: string;
|
|
13
|
+
queryKey: readonly [string, ...string[]];
|
|
14
|
+
endpoints: Pick<NextJsAuthEndpointSet, 'refresh' | 'logout' | 'loginStart' | 'loginFinish'>;
|
|
15
|
+
parseClientSession: (input: unknown) => TClientSession;
|
|
16
|
+
isSessionExpired: (session: TClientSession) => boolean;
|
|
17
|
+
};
|
|
18
|
+
export declare function defineReactAuthConfig<TActors extends readonly [AuthActor, ...AuthActor[]], TClientSession>(publicConfig: NextJsPublicAuthConfig<TActors, TClientSession>, input?: DefineReactAuthConfigInput): ReactAuthConfig<TActors, TClientSession>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function resolveNonEmptyString(value, fieldName) {
|
|
2
|
+
const trimmed = value.trim();
|
|
3
|
+
if (trimmed.length === 0) {
|
|
4
|
+
throw new Error(`${fieldName} must be a non-empty string.`);
|
|
5
|
+
}
|
|
6
|
+
return trimmed;
|
|
7
|
+
}
|
|
8
|
+
function resolveSessionStorageKey(key) {
|
|
9
|
+
return resolveNonEmptyString(key ?? 'direct-user-auth-session', 'sessionStorageKey');
|
|
10
|
+
}
|
|
11
|
+
function resolveQueryKey(queryKey) {
|
|
12
|
+
const resolved = queryKey ?? ['auth', 'session'];
|
|
13
|
+
if (resolved.length === 0) {
|
|
14
|
+
throw new Error('queryKey must contain at least one segment.');
|
|
15
|
+
}
|
|
16
|
+
const normalized = resolved.map(segment => resolveNonEmptyString(segment, 'queryKey segment'));
|
|
17
|
+
return normalized;
|
|
18
|
+
}
|
|
19
|
+
export function defineReactAuthConfig(publicConfig, input = {}) {
|
|
20
|
+
const nowUnix = input.nowUnix ?? (() => Math.floor(Date.now() / 1000));
|
|
21
|
+
const endpointSource = input.useInternalEndpoints
|
|
22
|
+
? publicConfig.endpoints.internal
|
|
23
|
+
: publicConfig.endpoints.public;
|
|
24
|
+
return {
|
|
25
|
+
kind: 'react',
|
|
26
|
+
publicConfig,
|
|
27
|
+
sessionStorageKey: resolveSessionStorageKey(input.sessionStorageKey),
|
|
28
|
+
queryKey: resolveQueryKey(input.queryKey),
|
|
29
|
+
endpoints: {
|
|
30
|
+
refresh: endpointSource.refresh,
|
|
31
|
+
logout: endpointSource.logout,
|
|
32
|
+
loginStart: endpointSource.loginStart,
|
|
33
|
+
loginFinish: endpointSource.loginFinish,
|
|
34
|
+
},
|
|
35
|
+
parseClientSession: value => publicConfig.base.session.parseClientSession(value),
|
|
36
|
+
isSessionExpired: session => publicConfig.base.session.isExpired(session, nowUnix()),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AuthActor } from '../types/auth-contract';
|
|
2
|
+
export type AccessTokenSource = 'bearer' | 'cookie';
|
|
3
|
+
export interface AccessTokenTransportInput {
|
|
4
|
+
authorizationHeader?: string;
|
|
5
|
+
cookies?: Record<string, string | undefined>;
|
|
6
|
+
}
|
|
7
|
+
export interface AccessTokenTransportAdapter<TActor extends AuthActor = AuthActor> {
|
|
8
|
+
extractAccessToken(input: {
|
|
9
|
+
transport: AccessTokenTransportInput;
|
|
10
|
+
actorHint?: TActor;
|
|
11
|
+
}): {
|
|
12
|
+
token: string | null;
|
|
13
|
+
source?: AccessTokenSource;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type PkceCodeMethod = 'S256' | 'plain';
|
|
2
|
+
export interface AuthorizationCodeAdapter<TUserId> {
|
|
3
|
+
create(input: {
|
|
4
|
+
userId: TUserId;
|
|
5
|
+
codeHash: string;
|
|
6
|
+
clientId: string;
|
|
7
|
+
redirectUri: string;
|
|
8
|
+
codeChallenge: string;
|
|
9
|
+
codeMethod: PkceCodeMethod;
|
|
10
|
+
expiresAtUnix: number;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
consume(codeHash: string, nowUnix: number): Promise<{
|
|
13
|
+
userId: TUserId;
|
|
14
|
+
clientId: string;
|
|
15
|
+
redirectUri: string;
|
|
16
|
+
codeChallenge: string;
|
|
17
|
+
codeMethod: PkceCodeMethod;
|
|
18
|
+
expiresAtUnix: number;
|
|
19
|
+
consumedAtUnix?: number | null;
|
|
20
|
+
} | null>;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthActor } from '../types/auth-contract';
|
|
2
|
+
export interface AuthorizationHooks<TActor extends AuthActor, TUserId> {
|
|
3
|
+
canCallMcpTool?(input: {
|
|
4
|
+
actor: TActor;
|
|
5
|
+
userId: TUserId;
|
|
6
|
+
clientId?: string;
|
|
7
|
+
toolName: string;
|
|
8
|
+
scopes: string[];
|
|
9
|
+
}): Promise<{
|
|
10
|
+
allowed: boolean;
|
|
11
|
+
reason?: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type { AccessTokenRevocationAdapter } from './access-token-revocation-adapter';
|
|
2
|
+
export type { AccessTokenSource, AccessTokenTransportAdapter, AccessTokenTransportInput, } from './access-token-transport-adapter';
|
|
3
|
+
export type { AuthorizationCodeAdapter, PkceCodeMethod as AdapterPkceCodeMethod, } from './authorization-code-adapter';
|
|
4
|
+
export type { AuthorizationHooks } from './authorization-hooks';
|
|
5
|
+
export type { LoginMethodAdapter } from './login-method-adapter';
|
|
6
|
+
export type { AuthAuditEvent, AuthAuditEventName, ObservabilityConfig, ObservabilityHooks, } from './observability-hooks';
|
|
7
|
+
export type { OAuthClientAdapter } from './oauth-client-adapter';
|
|
8
|
+
export type { OAuthClientManagementAdapter } from './oauth-client-management-adapter';
|
|
9
|
+
export type { OAuthGrantType } from './oauth-grant-type';
|
|
10
|
+
export type { OAuthPolicy } from './oauth-policy';
|
|
11
|
+
export type { PendingAuthRequestAdapter } from './pending-auth-request-adapter';
|
|
12
|
+
export type { RefreshTokenAdapter } from './refresh-token-adapter';
|
|
13
|
+
export type { SessionAdapter } from './session-adapter';
|
|
14
|
+
export type { TokenAdapter } from './token-adapter';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthActor } from '../types/auth-contract';
|
|
2
|
+
import type { OAuthGrantType } from './oauth-grant-type';
|
|
3
|
+
export interface OAuthClientAdapter<TActor extends AuthActor, TUserId> {
|
|
4
|
+
validateClient(input: {
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret: string | null;
|
|
7
|
+
grantType: OAuthGrantType;
|
|
8
|
+
}): Promise<{
|
|
9
|
+
clientId: string;
|
|
10
|
+
actor: TActor;
|
|
11
|
+
userId: TUserId;
|
|
12
|
+
} | null>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AuthActor } from '../types/auth-contract';
|
|
2
|
+
export interface OAuthClientManagementAdapter<TActor extends AuthActor, TUserId> {
|
|
3
|
+
create(input: {
|
|
4
|
+
userId: TUserId;
|
|
5
|
+
actor: TActor;
|
|
6
|
+
displayName: string;
|
|
7
|
+
requestedScopes?: string[];
|
|
8
|
+
}): Promise<{
|
|
9
|
+
clientId: string;
|
|
10
|
+
clientSecretPlaintext: string;
|
|
11
|
+
}>;
|
|
12
|
+
rotateSecret(clientId: string): Promise<{
|
|
13
|
+
clientSecretPlaintext: string;
|
|
14
|
+
}>;
|
|
15
|
+
setDisabled(clientId: string, disabled: boolean): Promise<void>;
|
|
16
|
+
listByUser(userId: TUserId): Promise<Array<{
|
|
17
|
+
clientId: string;
|
|
18
|
+
actor: TActor;
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
createdAtUnix: number;
|
|
21
|
+
lastRotatedAtUnix?: number | null;
|
|
22
|
+
}>>;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type OAuthGrantType = 'authorization_code' | 'refresh_token' | 'client_credentials';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AuthActor } from '../types/auth-contract';
|
|
2
|
+
import type { OAuthGrantType } from './oauth-grant-type';
|
|
3
|
+
export interface OAuthPolicy<TActor extends AuthActor = AuthActor> {
|
|
4
|
+
isAllowedClientId(clientId: string): boolean;
|
|
5
|
+
isAllowedRedirectUri(uri: string): boolean;
|
|
6
|
+
isAllowedActor(actor: TActor): boolean;
|
|
7
|
+
isAllowedGrantType?(grantType: OAuthGrantType, clientId: string): boolean;
|
|
8
|
+
requiredScopeForMcp: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AuthActor } from '../types/auth-contract';
|
|
2
|
+
export type AuthAuditEventName = 'access_token_issued' | 'access_token_rejected' | 'refresh_token_rotated' | 'refresh_token_reuse_detected' | 'session_revoked' | 'oauth_authorize_started' | 'oauth_code_issued' | 'oauth_token_exchanged' | 'oauth_client_authenticated' | 'mcp_tool_call_denied';
|
|
3
|
+
export interface AuthAuditEvent<TActor extends AuthActor = AuthActor> {
|
|
4
|
+
name: AuthAuditEventName;
|
|
5
|
+
atUnix: number;
|
|
6
|
+
requestId?: string;
|
|
7
|
+
actor?: TActor;
|
|
8
|
+
userId?: string;
|
|
9
|
+
clientId?: string;
|
|
10
|
+
sessionId?: string;
|
|
11
|
+
jti?: string;
|
|
12
|
+
reason?: string;
|
|
13
|
+
metadata?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
export interface ObservabilityHooks<TActor extends AuthActor = AuthActor> {
|
|
16
|
+
onAuditEvent?: (event: AuthAuditEvent<TActor>) => void | Promise<void>;
|
|
17
|
+
onMetric?: (input: {
|
|
18
|
+
name: string;
|
|
19
|
+
value?: number;
|
|
20
|
+
tags?: Record<string, string>;
|
|
21
|
+
}) => void | Promise<void>;
|
|
22
|
+
onError?: (input: {
|
|
23
|
+
where: string;
|
|
24
|
+
error: unknown;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
}) => void | Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export interface ObservabilityConfig<TActor extends AuthActor = AuthActor> {
|
|
29
|
+
hooks?: ObservabilityHooks<TActor>;
|
|
30
|
+
nonBlockingHooks?: boolean;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|