@amodalai/runtime 0.3.69 → 0.3.71
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/dist/src/auth/__fixtures__/custom-strategy.d.ts +8 -0
- package/dist/src/auth/__fixtures__/custom-strategy.js +27 -0
- package/dist/src/auth/__fixtures__/custom-strategy.js.map +1 -0
- package/dist/src/auth/compose.d.ts +55 -0
- package/dist/src/auth/compose.js +142 -0
- package/dist/src/auth/compose.js.map +1 -0
- package/dist/src/auth/compose.test.d.ts +6 -0
- package/dist/src/auth/compose.test.js +159 -0
- package/dist/src/auth/compose.test.js.map +1 -0
- package/dist/src/auth/config.d.ts +261 -0
- package/dist/src/auth/config.js +107 -0
- package/dist/src/auth/config.js.map +1 -0
- package/dist/src/auth/config.test.d.ts +6 -0
- package/dist/src/auth/config.test.js +85 -0
- package/dist/src/auth/config.test.js.map +1 -0
- package/dist/src/auth/factory.d.ts +19 -0
- package/dist/src/auth/factory.js +57 -0
- package/dist/src/auth/factory.js.map +1 -0
- package/dist/src/auth/factory.test.d.ts +6 -0
- package/dist/src/auth/factory.test.js +60 -0
- package/dist/src/auth/factory.test.js.map +1 -0
- package/dist/src/auth/index.d.ts +48 -0
- package/dist/src/auth/index.js +19 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/auth/strategies/amodal.d.ts +36 -0
- package/dist/src/auth/strategies/amodal.js +28 -0
- package/dist/src/auth/strategies/amodal.js.map +1 -0
- package/dist/src/auth/strategies/api-key.d.ts +41 -0
- package/dist/src/auth/strategies/api-key.js +63 -0
- package/dist/src/auth/strategies/api-key.js.map +1 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.d.ts +6 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.js +363 -0
- package/dist/src/auth/strategies/auth-modes.integration.test.js.map +1 -0
- package/dist/src/auth/strategies/cookie.d.ts +41 -0
- package/dist/src/auth/strategies/cookie.js +84 -0
- package/dist/src/auth/strategies/cookie.js.map +1 -0
- package/dist/src/auth/strategies/custom-loader.d.ts +17 -0
- package/dist/src/auth/strategies/custom-loader.js +37 -0
- package/dist/src/auth/strategies/custom-loader.js.map +1 -0
- package/dist/src/auth/strategies/header.d.ts +35 -0
- package/dist/src/auth/strategies/header.js +42 -0
- package/dist/src/auth/strategies/header.js.map +1 -0
- package/dist/src/auth/strategies/jwks.d.ts +38 -0
- package/dist/src/auth/strategies/jwks.js +86 -0
- package/dist/src/auth/strategies/jwks.js.map +1 -0
- package/dist/src/auth/strategies/jwt-secret.d.ts +25 -0
- package/dist/src/auth/strategies/jwt-secret.js +82 -0
- package/dist/src/auth/strategies/jwt-secret.js.map +1 -0
- package/dist/src/auth/strategies/jwt-secret.test.d.ts +6 -0
- package/dist/src/auth/strategies/jwt-secret.test.js +75 -0
- package/dist/src/auth/strategies/jwt-secret.test.js.map +1 -0
- package/dist/src/auth/strategies/none.d.ts +37 -0
- package/dist/src/auth/strategies/none.js +31 -0
- package/dist/src/auth/strategies/none.js.map +1 -0
- package/dist/src/auth/strategies/oidc.d.ts +48 -0
- package/dist/src/auth/strategies/oidc.integration.test.d.ts +6 -0
- package/dist/src/auth/strategies/oidc.integration.test.js +290 -0
- package/dist/src/auth/strategies/oidc.integration.test.js.map +1 -0
- package/dist/src/auth/strategies/oidc.js +284 -0
- package/dist/src/auth/strategies/oidc.js.map +1 -0
- package/dist/src/auth/strategies/oidc.test.d.ts +6 -0
- package/dist/src/auth/strategies/oidc.test.js +111 -0
- package/dist/src/auth/strategies/oidc.test.js.map +1 -0
- package/dist/src/auth/strategies/strategies.test.d.ts +6 -0
- package/dist/src/auth/strategies/strategies.test.js +190 -0
- package/dist/src/auth/strategies/strategies.test.js.map +1 -0
- package/dist/src/auth/types.d.ts +95 -0
- package/dist/src/auth/types.js +7 -0
- package/dist/src/auth/types.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/routes/session-resolver.d.ts +10 -10
- package/dist/src/routes/session-resolver.js +33 -17
- package/dist/src/routes/session-resolver.js.map +1 -1
- package/dist/src/routes/session-resolver.test.js +121 -80
- package/dist/src/routes/session-resolver.test.js.map +1 -1
- package/dist/src/session/drizzle-session-store.d.ts +8 -12
- package/dist/src/session/drizzle-session-store.js +38 -37
- package/dist/src/session/drizzle-session-store.js.map +1 -1
- package/dist/src/session/store.d.ts +5 -5
- package/dist/src/session/store.js +54 -38
- package/dist/src/session/store.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -4
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Pluggable auth — the Warden-shape primitive layer.
|
|
8
|
+
*
|
|
9
|
+
* import {authenticate, JwksAuthStrategy} from '@amodalai/runtime/auth';
|
|
10
|
+
*
|
|
11
|
+
* const platformJwt = new JwksAuthStrategy({jwksUrl: '...'});
|
|
12
|
+
* const endUser = new OidcStrategy({...});
|
|
13
|
+
*
|
|
14
|
+
* // Per-route strategy lists. Studio routes only ever see platformJwt;
|
|
15
|
+
* // chat routes accept either platformJwt (Studio testing) OR endUser.
|
|
16
|
+
* app.use('/api/files', authenticate(platformJwt));
|
|
17
|
+
* app.use('/chat', authenticate(platformJwt, endUser));
|
|
18
|
+
*
|
|
19
|
+
* // Mount any login-flow routes a strategy registers.
|
|
20
|
+
* app.use(authRouter(endUser));
|
|
21
|
+
*
|
|
22
|
+
* Single-winner chain semantics: first strategy whose `valid(req)` is
|
|
23
|
+
* true and `authenticate(req)` returns `'authenticated'` wins. No
|
|
24
|
+
* merging, no implicit identity overrides.
|
|
25
|
+
*/
|
|
26
|
+
export type { AuthStrategy, AuthResult, AuthSession } from './types.js';
|
|
27
|
+
export { authenticate, authRouter, getSession } from './compose.js';
|
|
28
|
+
export type { AuthLogEvent, AuthenticateOptions } from './compose.js';
|
|
29
|
+
export { JwksAuthStrategy } from './strategies/jwks.js';
|
|
30
|
+
export type { JwksAuthStrategyOptions } from './strategies/jwks.js';
|
|
31
|
+
export { ApiKeyAuthStrategy } from './strategies/api-key.js';
|
|
32
|
+
export type { ApiKeyAuthStrategyOptions, ApiKeyValidationResult, } from './strategies/api-key.js';
|
|
33
|
+
export { HeaderAuthStrategy } from './strategies/header.js';
|
|
34
|
+
export type { HeaderAuthStrategyOptions } from './strategies/header.js';
|
|
35
|
+
export { NoneAuthStrategy } from './strategies/none.js';
|
|
36
|
+
export type { NoneAuthStrategyOptions } from './strategies/none.js';
|
|
37
|
+
export { CookieSessionStrategy } from './strategies/cookie.js';
|
|
38
|
+
export type { CookieSessionStrategyOptions } from './strategies/cookie.js';
|
|
39
|
+
export { JwtSecretAuthStrategy } from './strategies/jwt-secret.js';
|
|
40
|
+
export type { JwtSecretAuthStrategyOptions } from './strategies/jwt-secret.js';
|
|
41
|
+
export { OidcAuthStrategy } from './strategies/oidc.js';
|
|
42
|
+
export type { OidcAuthStrategyOptions } from './strategies/oidc.js';
|
|
43
|
+
export { AmodalAuthStrategy } from './strategies/amodal.js';
|
|
44
|
+
export type { AmodalAuthStrategyOptions } from './strategies/amodal.js';
|
|
45
|
+
export { AuthConfigSchema, parseAuthConfig } from './config.js';
|
|
46
|
+
export type { AuthConfig, NoneAuthConfig, JwtSecretAuthConfig, OidcAuthConfig, HeaderAuthConfig, CustomAuthConfig, AmodalAuthConfig, } from './config.js';
|
|
47
|
+
export { createAuthStrategy } from './factory.js';
|
|
48
|
+
export { loadCustomStrategy } from './strategies/custom-loader.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
export { authenticate, authRouter, getSession } from './compose.js';
|
|
7
|
+
export { JwksAuthStrategy } from './strategies/jwks.js';
|
|
8
|
+
export { ApiKeyAuthStrategy } from './strategies/api-key.js';
|
|
9
|
+
export { HeaderAuthStrategy } from './strategies/header.js';
|
|
10
|
+
export { NoneAuthStrategy } from './strategies/none.js';
|
|
11
|
+
export { CookieSessionStrategy } from './strategies/cookie.js';
|
|
12
|
+
export { JwtSecretAuthStrategy } from './strategies/jwt-secret.js';
|
|
13
|
+
export { OidcAuthStrategy } from './strategies/oidc.js';
|
|
14
|
+
export { AmodalAuthStrategy } from './strategies/amodal.js';
|
|
15
|
+
// Config-driven auth — `auth` field in `amodal.json` → AuthStrategy
|
|
16
|
+
export { AuthConfigSchema, parseAuthConfig } from './config.js';
|
|
17
|
+
export { createAuthStrategy } from './factory.js';
|
|
18
|
+
export { loadCustomStrategy } from './strategies/custom-loader.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwBH,OAAO,EAAC,YAAY,EAAE,UAAU,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAGlE,OAAO,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAC,kBAAkB,EAAC,MAAM,yBAAyB,CAAC;AAM3D,OAAO,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAG1D,OAAO,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAC,qBAAqB,EAAC,MAAM,wBAAwB,CAAC;AAG7D,OAAO,EAAC,qBAAqB,EAAC,MAAM,4BAA4B,CAAC;AAGjE,OAAO,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAC,kBAAkB,EAAC,MAAM,wBAAwB,CAAC;AAG1D,oEAAoE;AACpE,OAAO,EAAC,gBAAgB,EAAE,eAAe,EAAC,MAAM,aAAa,CAAC;AAU9D,OAAO,EAAC,kBAAkB,EAAC,MAAM,cAAc,CAAC;AAChD,OAAO,EAAC,kBAAkB,EAAC,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* AmodalAuthStrategy — "Sign in with Amodal."
|
|
8
|
+
*
|
|
9
|
+
* The zero-config option for agent owners on the Amodal cloud. End users
|
|
10
|
+
* sign in with their existing Amodal account; the runtime verifies the
|
|
11
|
+
* platform-issued JWT against Amodal's JWKS. cf-worker handles the
|
|
12
|
+
* redirect-to-login dance upstream — by the time a request reaches the
|
|
13
|
+
* runtime, it carries a valid platform JWT in `Authorization: Bearer`.
|
|
14
|
+
*
|
|
15
|
+
* Internally just a `JwksAuthStrategy` preconfigured with Amodal's JWKS
|
|
16
|
+
* URL and issuer. Self-hosters running their own Amodal-equivalent
|
|
17
|
+
* platform can override both via constructor options.
|
|
18
|
+
*/
|
|
19
|
+
import type { Request } from 'express';
|
|
20
|
+
import type { AuthResult, AuthStrategy } from '../types.js';
|
|
21
|
+
export interface AmodalAuthStrategyOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Override the platform JWKS URL. Defaults to `AMODAL_JWKS_URL` env
|
|
24
|
+
* var, then to `https://api.amodalai.com/.well-known/jwks.json`.
|
|
25
|
+
*/
|
|
26
|
+
jwksUrl?: string;
|
|
27
|
+
/** Override the expected `iss` claim. Defaults to `'aitize-platform'`. */
|
|
28
|
+
issuer?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare class AmodalAuthStrategy implements AuthStrategy {
|
|
31
|
+
readonly name = "amodal";
|
|
32
|
+
private readonly inner;
|
|
33
|
+
constructor(options?: AmodalAuthStrategyOptions);
|
|
34
|
+
valid(req: Request): boolean;
|
|
35
|
+
authenticate(req: Request): Promise<AuthResult>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { JwksAuthStrategy } from './jwks.js';
|
|
7
|
+
const DEFAULT_AMODAL_JWKS_URL = 'https://api.amodalai.com/.well-known/jwks.json';
|
|
8
|
+
const DEFAULT_AMODAL_ISSUER = 'aitize-platform';
|
|
9
|
+
export class AmodalAuthStrategy {
|
|
10
|
+
name = 'amodal';
|
|
11
|
+
inner;
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.inner = new JwksAuthStrategy({
|
|
14
|
+
jwksUrl: options.jwksUrl ??
|
|
15
|
+
process.env['AMODAL_JWKS_URL'] ??
|
|
16
|
+
DEFAULT_AMODAL_JWKS_URL,
|
|
17
|
+
issuer: options.issuer ?? DEFAULT_AMODAL_ISSUER,
|
|
18
|
+
authMethod: 'amodal',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
valid(req) {
|
|
22
|
+
return this.inner.valid(req);
|
|
23
|
+
}
|
|
24
|
+
authenticate(req) {
|
|
25
|
+
return this.inner.authenticate(req);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=amodal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amodal.js","sourceRoot":"","sources":["../../../../src/auth/strategies/amodal.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiBH,OAAO,EAAC,gBAAgB,EAAC,MAAM,WAAW,CAAC;AAY3C,MAAM,uBAAuB,GAAG,gDAAgD,CAAC;AACjF,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAEhD,MAAM,OAAO,kBAAkB;IACpB,IAAI,GAAG,QAAQ,CAAC;IACR,KAAK,CAAmB;IAEzC,YAAY,UAAqC,EAAE;QACjD,IAAI,CAAC,KAAK,GAAG,IAAI,gBAAgB,CAAC;YAChC,OAAO,EACL,OAAO,CAAC,OAAO;gBACf,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;gBAC9B,uBAAuB;YACzB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,qBAAqB;YAC/C,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAY;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,YAAY,CAAC,GAAY;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;CACF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import type { Request } from 'express';
|
|
7
|
+
import type { AuthResult, AuthStrategy } from '../types.js';
|
|
8
|
+
export interface ApiKeyValidationResult {
|
|
9
|
+
/** Required — the principal id this key represents. */
|
|
10
|
+
userId: string;
|
|
11
|
+
email?: string;
|
|
12
|
+
/** Optional — the agent this key is scoped to. */
|
|
13
|
+
agentId?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ApiKeyAuthStrategyOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Validate the API key. Return `null` for "not a valid key" (chain
|
|
18
|
+
* rejects with 401). Throw to signal an upstream error (callers can
|
|
19
|
+
* upgrade these to 502s by wrapping the strategy if desired).
|
|
20
|
+
*/
|
|
21
|
+
validate: (apiKey: string) => Promise<ApiKeyValidationResult | null>;
|
|
22
|
+
/** Cache TTL for successful validations (ms). Defaults to 5 minutes. */
|
|
23
|
+
cacheTtlMs?: number;
|
|
24
|
+
/** Cap on the LRU cache. Defaults to 10,000 entries. */
|
|
25
|
+
cacheMaxEntries?: number;
|
|
26
|
+
/** Token prefix this strategy matches. Defaults to `'ak_'`. */
|
|
27
|
+
keyPrefix?: string;
|
|
28
|
+
/** Override `AuthSession.method`. Defaults to `'api-key'`. */
|
|
29
|
+
authMethod?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare class ApiKeyAuthStrategy implements AuthStrategy {
|
|
32
|
+
readonly name = "api-key";
|
|
33
|
+
private readonly validate;
|
|
34
|
+
private readonly keyPrefix;
|
|
35
|
+
private readonly authMethod;
|
|
36
|
+
private readonly cache;
|
|
37
|
+
constructor(options: ApiKeyAuthStrategyOptions);
|
|
38
|
+
valid(req: Request): boolean;
|
|
39
|
+
authenticate(req: Request): Promise<AuthResult>;
|
|
40
|
+
private buildSession;
|
|
41
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* ApiKeyAuthStrategy — `ak_*` Bearer tokens, validated via a caller-
|
|
8
|
+
* supplied callback (cloud's `/api/me`, a self-hoster's own DB query,
|
|
9
|
+
* etc.). LRU-cached so repeated requests with the same key skip the
|
|
10
|
+
* validation round-trip.
|
|
11
|
+
*/
|
|
12
|
+
import { LRUCache } from 'lru-cache';
|
|
13
|
+
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
14
|
+
const DEFAULT_CACHE_MAX = 10_000;
|
|
15
|
+
export class ApiKeyAuthStrategy {
|
|
16
|
+
name = 'api-key';
|
|
17
|
+
validate;
|
|
18
|
+
keyPrefix;
|
|
19
|
+
authMethod;
|
|
20
|
+
cache;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.validate = options.validate;
|
|
23
|
+
this.keyPrefix = options.keyPrefix ?? 'ak_';
|
|
24
|
+
this.authMethod = options.authMethod ?? 'api-key';
|
|
25
|
+
this.cache = new LRUCache({
|
|
26
|
+
max: options.cacheMaxEntries ?? DEFAULT_CACHE_MAX,
|
|
27
|
+
ttl: options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
valid(req) {
|
|
31
|
+
const auth = req.headers['authorization'];
|
|
32
|
+
if (typeof auth !== 'string' || !auth.startsWith('Bearer '))
|
|
33
|
+
return false;
|
|
34
|
+
const token = auth.slice(7);
|
|
35
|
+
return token.startsWith(this.keyPrefix);
|
|
36
|
+
}
|
|
37
|
+
async authenticate(req) {
|
|
38
|
+
const auth = req.headers['authorization'];
|
|
39
|
+
if (typeof auth !== 'string')
|
|
40
|
+
return { kind: 'rejected', reason: 'No bearer token' };
|
|
41
|
+
const token = auth.slice(7);
|
|
42
|
+
const cached = this.cache.get(token);
|
|
43
|
+
if (cached) {
|
|
44
|
+
return { kind: 'authenticated', session: this.buildSession(cached) };
|
|
45
|
+
}
|
|
46
|
+
const result = await this.validate(token);
|
|
47
|
+
if (!result)
|
|
48
|
+
return { kind: 'rejected', reason: 'Invalid API key' };
|
|
49
|
+
this.cache.set(token, result);
|
|
50
|
+
return { kind: 'authenticated', session: this.buildSession(result) };
|
|
51
|
+
}
|
|
52
|
+
buildSession(result) {
|
|
53
|
+
return {
|
|
54
|
+
user: {
|
|
55
|
+
id: result.userId,
|
|
56
|
+
...(result.email ? { email: result.email } : {}),
|
|
57
|
+
},
|
|
58
|
+
method: this.authMethod,
|
|
59
|
+
...(result.agentId ? { agentId: result.agentId } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=api-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key.js","sourceRoot":"","sources":["../../../../src/auth/strategies/api-key.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,OAAO,EAAC,QAAQ,EAAC,MAAM,WAAW,CAAC;AA6BnC,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAC3C,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC,MAAM,OAAO,kBAAkB;IACpB,IAAI,GAAG,SAAS,CAAC;IACT,QAAQ,CAAwC;IAChD,SAAS,CAAS;IAClB,UAAU,CAAS;IACnB,KAAK,CAA2C;IAEjE,YAAY,OAAkC;QAC5C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;QAC5C,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,SAAS,CAAC;QAClD,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAiC;YACxD,GAAG,EAAE,OAAO,CAAC,eAAe,IAAI,iBAAiB;YACjD,GAAG,EAAE,OAAO,CAAC,UAAU,IAAI,oBAAoB;SAChD,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAY;QAChB,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAY;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC1C,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAC,CAAC;QACnF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,EAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAC,CAAC;QACrE,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM;YAAE,OAAO,EAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAC,CAAC;QAClE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC9B,OAAO,EAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAC,CAAC;IACrE,CAAC;IAEO,YAAY,CAAC,MAA8B;QACjD,OAAO;YACL,IAAI,EAAE;gBACJ,EAAE,EAAE,MAAM,CAAC,MAAM;gBACjB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/C;YACD,MAAM,EAAE,IAAI,CAAC,UAAU;YACvB,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACrD,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* End-to-end tests for the simpler auth modes — `none`, `header`,
|
|
8
|
+
* `jwt_secret`, `custom`, `amodal` — exercised through a real Express
|
|
9
|
+
* app over real HTTP. The OIDC strategy gets its own integration file
|
|
10
|
+
* (`oidc.integration.test.ts`) since it requires booting a full IdP.
|
|
11
|
+
*
|
|
12
|
+
* Each test:
|
|
13
|
+
* 1. Constructs the strategy via `createAuthStrategy(config)` so the
|
|
14
|
+
* factory's wiring is on the hot path (not just the strategy's
|
|
15
|
+
* constructor).
|
|
16
|
+
* 2. Mounts it on a real Express server bound to a random port.
|
|
17
|
+
* 3. Hits a protected route with appropriate credentials.
|
|
18
|
+
* 4. Asserts both the success and rejection paths.
|
|
19
|
+
*/
|
|
20
|
+
import http from 'node:http';
|
|
21
|
+
import { randomBytes, generateKeyPairSync } from 'node:crypto';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { dirname, resolve } from 'node:path';
|
|
24
|
+
import express from 'express';
|
|
25
|
+
import { SignJWT, exportJWK } from 'jose';
|
|
26
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
27
|
+
import { createAuthStrategy } from '../factory.js';
|
|
28
|
+
import { authenticate, getSession } from '../compose.js';
|
|
29
|
+
async function startProtectedApp(strategy) {
|
|
30
|
+
const app = express();
|
|
31
|
+
app.get('/protected', authenticate(strategy), (_req, res) => {
|
|
32
|
+
const session = getSession(res);
|
|
33
|
+
res.json({ user: session?.user, method: session?.method });
|
|
34
|
+
});
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const server = http.createServer(app);
|
|
37
|
+
server.on('error', reject);
|
|
38
|
+
server.listen(0, '127.0.0.1', () => {
|
|
39
|
+
const addr = server.address();
|
|
40
|
+
resolve({
|
|
41
|
+
url: `http://127.0.0.1:${addr.port}`,
|
|
42
|
+
close: () => new Promise((closeResolve, closeReject) => {
|
|
43
|
+
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async function getJson(url, init = {}) {
|
|
50
|
+
const res = await fetch(url, init);
|
|
51
|
+
let body = {};
|
|
52
|
+
if (res.headers.get('content-type')?.includes('application/json')) {
|
|
53
|
+
body = (await res.json());
|
|
54
|
+
}
|
|
55
|
+
return { status: res.status, body };
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// none
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
describe('none mode — integration', () => {
|
|
61
|
+
let app;
|
|
62
|
+
beforeAll(async () => {
|
|
63
|
+
const strategy = await createAuthStrategy({ type: 'none' });
|
|
64
|
+
app = await startProtectedApp(strategy);
|
|
65
|
+
});
|
|
66
|
+
afterAll(async () => {
|
|
67
|
+
if (app)
|
|
68
|
+
await app.close();
|
|
69
|
+
});
|
|
70
|
+
it('lets every request through with the synthesized anonymous user', async () => {
|
|
71
|
+
const { status, body } = await getJson(`${app.url}/protected`);
|
|
72
|
+
expect(status).toBe(200);
|
|
73
|
+
expect(body.user?.id).toBe('anonymous');
|
|
74
|
+
expect(body.method).toBe('none');
|
|
75
|
+
});
|
|
76
|
+
it('respects a custom userId override', async () => {
|
|
77
|
+
const strategy = await createAuthStrategy({ type: 'none', userId: 'guest' });
|
|
78
|
+
const guestApp = await startProtectedApp(strategy);
|
|
79
|
+
try {
|
|
80
|
+
const { status, body } = await getJson(`${guestApp.url}/protected`);
|
|
81
|
+
expect(status).toBe(200);
|
|
82
|
+
expect(body.user?.id).toBe('guest');
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
await guestApp.close();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// header
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
describe('header mode — integration', () => {
|
|
93
|
+
let app;
|
|
94
|
+
beforeAll(async () => {
|
|
95
|
+
const strategy = await createAuthStrategy({ type: 'header' });
|
|
96
|
+
app = await startProtectedApp(strategy);
|
|
97
|
+
});
|
|
98
|
+
afterAll(async () => {
|
|
99
|
+
if (app)
|
|
100
|
+
await app.close();
|
|
101
|
+
});
|
|
102
|
+
it('reads identity from the default X-Auth-User header', async () => {
|
|
103
|
+
const { status, body } = await getJson(`${app.url}/protected`, {
|
|
104
|
+
headers: { 'X-Auth-User': 'alice' },
|
|
105
|
+
});
|
|
106
|
+
expect(status).toBe(200);
|
|
107
|
+
expect(body.user?.id).toBe('alice');
|
|
108
|
+
expect(body.method).toBe('header');
|
|
109
|
+
});
|
|
110
|
+
it('rejects requests with no identity header', async () => {
|
|
111
|
+
const { status } = await getJson(`${app.url}/protected`);
|
|
112
|
+
expect(status).toBe(401);
|
|
113
|
+
});
|
|
114
|
+
it('honours a configured headerName', async () => {
|
|
115
|
+
const strategy = await createAuthStrategy({
|
|
116
|
+
type: 'header',
|
|
117
|
+
headerName: 'X-Forwarded-User',
|
|
118
|
+
});
|
|
119
|
+
const customApp = await startProtectedApp(strategy);
|
|
120
|
+
try {
|
|
121
|
+
const ok = await getJson(`${customApp.url}/protected`, {
|
|
122
|
+
headers: { 'X-Forwarded-User': 'bob' },
|
|
123
|
+
});
|
|
124
|
+
expect(ok.status).toBe(200);
|
|
125
|
+
expect(ok.body.user?.id).toBe('bob');
|
|
126
|
+
// wrong header → rejected
|
|
127
|
+
const bad = await getJson(`${customApp.url}/protected`, {
|
|
128
|
+
headers: { 'X-Auth-User': 'eve' },
|
|
129
|
+
});
|
|
130
|
+
expect(bad.status).toBe(401);
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
await customApp.close();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// jwt_secret
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
describe('jwt_secret mode — integration', () => {
|
|
141
|
+
const SECRET = 'shared-hmac-secret-please-rotate';
|
|
142
|
+
let app;
|
|
143
|
+
async function mintToken(claims = {}, ttl = 300) {
|
|
144
|
+
const key = new TextEncoder().encode(SECRET);
|
|
145
|
+
return new SignJWT({ sub: 'user-1', email: 'u1@example.com', name: 'User One', ...claims })
|
|
146
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
147
|
+
.setIssuedAt()
|
|
148
|
+
.setExpirationTime(`${ttl}s`)
|
|
149
|
+
.sign(key);
|
|
150
|
+
}
|
|
151
|
+
beforeAll(async () => {
|
|
152
|
+
const strategy = await createAuthStrategy({ type: 'jwt_secret', secret: SECRET });
|
|
153
|
+
app = await startProtectedApp(strategy);
|
|
154
|
+
});
|
|
155
|
+
afterAll(async () => {
|
|
156
|
+
if (app)
|
|
157
|
+
await app.close();
|
|
158
|
+
});
|
|
159
|
+
it('accepts a valid HS256 bearer token', async () => {
|
|
160
|
+
const token = await mintToken();
|
|
161
|
+
const { status, body } = await getJson(`${app.url}/protected`, {
|
|
162
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
163
|
+
});
|
|
164
|
+
expect(status).toBe(200);
|
|
165
|
+
expect(body.user?.id).toBe('user-1');
|
|
166
|
+
expect(body.user?.email).toBe('u1@example.com');
|
|
167
|
+
});
|
|
168
|
+
it('rejects a tampered signature', async () => {
|
|
169
|
+
const token = await mintToken();
|
|
170
|
+
const tampered = `${token.slice(0, -3)}AAA`;
|
|
171
|
+
const { status } = await getJson(`${app.url}/protected`, {
|
|
172
|
+
headers: { Authorization: `Bearer ${tampered}` },
|
|
173
|
+
});
|
|
174
|
+
expect(status).toBe(401);
|
|
175
|
+
});
|
|
176
|
+
it('rejects a token signed with a different secret', async () => {
|
|
177
|
+
const wrongKey = new TextEncoder().encode('different-secret-of-similar-length');
|
|
178
|
+
const token = await new SignJWT({ sub: 'imposter' })
|
|
179
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
180
|
+
.setIssuedAt()
|
|
181
|
+
.setExpirationTime('5m')
|
|
182
|
+
.sign(wrongKey);
|
|
183
|
+
const { status } = await getJson(`${app.url}/protected`, {
|
|
184
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
185
|
+
});
|
|
186
|
+
expect(status).toBe(401);
|
|
187
|
+
});
|
|
188
|
+
it('rejects when no Authorization header is sent', async () => {
|
|
189
|
+
const { status } = await getJson(`${app.url}/protected`);
|
|
190
|
+
expect(status).toBe(401);
|
|
191
|
+
});
|
|
192
|
+
it('enforces issuer when configured', async () => {
|
|
193
|
+
const strategy = await createAuthStrategy({
|
|
194
|
+
type: 'jwt_secret',
|
|
195
|
+
secret: SECRET,
|
|
196
|
+
issuer: 'expected-issuer',
|
|
197
|
+
});
|
|
198
|
+
const issuerApp = await startProtectedApp(strategy);
|
|
199
|
+
try {
|
|
200
|
+
const goodKey = new TextEncoder().encode(SECRET);
|
|
201
|
+
const goodToken = await new SignJWT({ sub: 'user-1' })
|
|
202
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
203
|
+
.setIssuedAt()
|
|
204
|
+
.setExpirationTime('5m')
|
|
205
|
+
.setIssuer('expected-issuer')
|
|
206
|
+
.sign(goodKey);
|
|
207
|
+
const badToken = await new SignJWT({ sub: 'user-1' })
|
|
208
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
209
|
+
.setIssuedAt()
|
|
210
|
+
.setExpirationTime('5m')
|
|
211
|
+
.setIssuer('other-issuer')
|
|
212
|
+
.sign(goodKey);
|
|
213
|
+
const ok = await getJson(`${issuerApp.url}/protected`, {
|
|
214
|
+
headers: { Authorization: `Bearer ${goodToken}` },
|
|
215
|
+
});
|
|
216
|
+
expect(ok.status).toBe(200);
|
|
217
|
+
const bad = await getJson(`${issuerApp.url}/protected`, {
|
|
218
|
+
headers: { Authorization: `Bearer ${badToken}` },
|
|
219
|
+
});
|
|
220
|
+
expect(bad.status).toBe(401);
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
await issuerApp.close();
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// custom
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
describe('custom mode — integration', () => {
|
|
231
|
+
let app;
|
|
232
|
+
beforeAll(async () => {
|
|
233
|
+
// Resolve the fixture path relative to this test file so the dynamic
|
|
234
|
+
// import works regardless of cwd.
|
|
235
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
236
|
+
const modulePath = resolve(here, '../__fixtures__/custom-strategy.ts');
|
|
237
|
+
const strategy = await createAuthStrategy({ type: 'custom', module: modulePath });
|
|
238
|
+
app = await startProtectedApp(strategy);
|
|
239
|
+
});
|
|
240
|
+
afterAll(async () => {
|
|
241
|
+
if (app)
|
|
242
|
+
await app.close();
|
|
243
|
+
});
|
|
244
|
+
it('authenticates when the fixture token matches', async () => {
|
|
245
|
+
const { status, body } = await getJson(`${app.url}/protected`, {
|
|
246
|
+
headers: { 'X-Custom-Token': 'secret-value' },
|
|
247
|
+
});
|
|
248
|
+
expect(status).toBe(200);
|
|
249
|
+
expect(body.user?.id).toBe('custom-user');
|
|
250
|
+
expect(body.method).toBe('custom-test');
|
|
251
|
+
});
|
|
252
|
+
it('rejects when the fixture token is wrong', async () => {
|
|
253
|
+
const { status } = await getJson(`${app.url}/protected`, {
|
|
254
|
+
headers: { 'X-Custom-Token': 'not-the-secret' },
|
|
255
|
+
});
|
|
256
|
+
expect(status).toBe(401);
|
|
257
|
+
});
|
|
258
|
+
it('rejects when the fixture header is missing', async () => {
|
|
259
|
+
const { status } = await getJson(`${app.url}/protected`);
|
|
260
|
+
expect(status).toBe(401);
|
|
261
|
+
});
|
|
262
|
+
it('throws at construction when the module path does not exist', async () => {
|
|
263
|
+
await expect(createAuthStrategy({ type: 'custom', module: '/path/that/does/not/exist.ts' })).rejects.toThrow(/Failed to load custom auth strategy/);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
async function startJwksServer() {
|
|
267
|
+
// jose's exportJWK + SignJWT accept Node's KeyObject as a valid KeyLike.
|
|
268
|
+
const { publicKey, privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
|
|
269
|
+
const publicJwk = await exportJWK(publicKey);
|
|
270
|
+
const kid = randomBytes(8).toString('hex');
|
|
271
|
+
publicJwk.kid = kid;
|
|
272
|
+
publicJwk.alg = 'RS256';
|
|
273
|
+
publicJwk.use = 'sig';
|
|
274
|
+
const app = express();
|
|
275
|
+
app.get('/.well-known/jwks.json', (_req, res) => {
|
|
276
|
+
res.json({ keys: [publicJwk] });
|
|
277
|
+
});
|
|
278
|
+
const signingKey = privateKey;
|
|
279
|
+
return new Promise((resolve, reject) => {
|
|
280
|
+
const server = http.createServer(app);
|
|
281
|
+
server.on('error', reject);
|
|
282
|
+
server.listen(0, '127.0.0.1', () => {
|
|
283
|
+
const addr = server.address();
|
|
284
|
+
const url = `http://127.0.0.1:${addr.port}`;
|
|
285
|
+
resolve({
|
|
286
|
+
url,
|
|
287
|
+
jwksUrl: `${url}/.well-known/jwks.json`,
|
|
288
|
+
signingKey,
|
|
289
|
+
kid,
|
|
290
|
+
close: () => new Promise((closeResolve, closeReject) => {
|
|
291
|
+
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
292
|
+
}),
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
describe('amodal mode — integration', () => {
|
|
298
|
+
const ISSUER = 'integration-test-platform';
|
|
299
|
+
let jwks;
|
|
300
|
+
let app;
|
|
301
|
+
async function mintPlatformToken(claims = {}, issuer = ISSUER) {
|
|
302
|
+
return new SignJWT({ sub: 'amodal-user-1', email: 'a1@amodal.test', ...claims })
|
|
303
|
+
.setProtectedHeader({ alg: 'RS256', kid: jwks.kid })
|
|
304
|
+
.setIssuedAt()
|
|
305
|
+
.setIssuer(issuer)
|
|
306
|
+
.setExpirationTime('5m')
|
|
307
|
+
.sign(jwks.signingKey);
|
|
308
|
+
}
|
|
309
|
+
beforeAll(async () => {
|
|
310
|
+
jwks = await startJwksServer();
|
|
311
|
+
const strategy = await createAuthStrategy({
|
|
312
|
+
type: 'amodal',
|
|
313
|
+
jwksUrl: jwks.jwksUrl,
|
|
314
|
+
issuer: ISSUER,
|
|
315
|
+
});
|
|
316
|
+
app = await startProtectedApp(strategy);
|
|
317
|
+
});
|
|
318
|
+
afterAll(async () => {
|
|
319
|
+
if (app)
|
|
320
|
+
await app.close();
|
|
321
|
+
if (jwks)
|
|
322
|
+
await jwks.close();
|
|
323
|
+
});
|
|
324
|
+
it('accepts a platform-signed JWT verified against the JWKS', async () => {
|
|
325
|
+
const token = await mintPlatformToken();
|
|
326
|
+
const { status, body } = await getJson(`${app.url}/protected`, {
|
|
327
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
328
|
+
});
|
|
329
|
+
expect(status).toBe(200);
|
|
330
|
+
expect(body.user?.id).toBe('amodal-user-1');
|
|
331
|
+
expect(body.method).toBe('amodal');
|
|
332
|
+
});
|
|
333
|
+
it('rejects a token with the wrong issuer', async () => {
|
|
334
|
+
const token = await mintPlatformToken({}, 'someone-elses-platform');
|
|
335
|
+
const { status } = await getJson(`${app.url}/protected`, {
|
|
336
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
337
|
+
});
|
|
338
|
+
expect(status).toBe(401);
|
|
339
|
+
});
|
|
340
|
+
it('rejects a token signed by a different key', async () => {
|
|
341
|
+
const otherJwks = await startJwksServer();
|
|
342
|
+
try {
|
|
343
|
+
const token = await new SignJWT({ sub: 'imposter' })
|
|
344
|
+
.setProtectedHeader({ alg: 'RS256', kid: otherJwks.kid })
|
|
345
|
+
.setIssuedAt()
|
|
346
|
+
.setIssuer(ISSUER)
|
|
347
|
+
.setExpirationTime('5m')
|
|
348
|
+
.sign(otherJwks.signingKey);
|
|
349
|
+
const { status } = await getJson(`${app.url}/protected`, {
|
|
350
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
351
|
+
});
|
|
352
|
+
expect(status).toBe(401);
|
|
353
|
+
}
|
|
354
|
+
finally {
|
|
355
|
+
await otherJwks.close();
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
it('rejects when no bearer token is sent', async () => {
|
|
359
|
+
const { status } = await getJson(`${app.url}/protected`);
|
|
360
|
+
expect(status).toBe(401);
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
//# sourceMappingURL=auth-modes.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-modes.integration.test.js","sourceRoot":"","sources":["../../../../src/auth/strategies/auth-modes.integration.test.ts"],"names":[],"mappings":"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"}
|