@technomoron/api-server-base 2.0.0-beta.2 → 2.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.txt +81 -28
- package/dist/cjs/api-module.cjs +9 -0
- package/dist/cjs/api-module.d.ts +7 -4
- package/dist/cjs/api-server-base.cjs +607 -99
- package/dist/cjs/api-server-base.d.ts +80 -23
- package/dist/cjs/auth-api/auth-module.d.ts +23 -3
- package/dist/cjs/auth-api/auth-module.js +320 -124
- package/dist/cjs/auth-api/compat-auth-storage.d.ts +7 -5
- package/dist/cjs/auth-api/compat-auth-storage.js +15 -3
- package/dist/cjs/auth-api/mem-auth-store.d.ts +5 -3
- package/dist/cjs/auth-api/mem-auth-store.js +14 -28
- package/dist/cjs/auth-api/module.d.ts +1 -1
- package/dist/cjs/auth-api/sql-auth-store.d.ts +16 -4
- package/dist/cjs/auth-api/sql-auth-store.js +43 -30
- package/dist/cjs/auth-api/storage.d.ts +6 -4
- package/dist/cjs/auth-api/storage.js +15 -5
- package/dist/cjs/auth-api/types.d.ts +7 -2
- package/dist/cjs/auth-api/user-id.d.ts +5 -0
- package/dist/cjs/auth-api/user-id.js +38 -0
- package/dist/cjs/auth-cookie-options.d.ts +11 -0
- package/dist/cjs/auth-cookie-options.js +66 -0
- package/dist/cjs/index.cjs +4 -14
- package/dist/cjs/index.d.ts +4 -9
- package/dist/cjs/oauth/memory.d.ts +6 -0
- package/dist/cjs/oauth/memory.js +44 -11
- package/dist/cjs/oauth/models.d.ts +7 -2
- package/dist/cjs/oauth/models.js +10 -21
- package/dist/cjs/oauth/sequelize.d.ts +10 -48
- package/dist/cjs/oauth/sequelize.js +44 -99
- package/dist/cjs/oauth/types.d.ts +1 -0
- package/dist/cjs/passkey/base.d.ts +2 -0
- package/dist/cjs/passkey/config.d.ts +2 -0
- package/dist/cjs/passkey/config.js +26 -0
- package/dist/cjs/passkey/memory.d.ts +8 -0
- package/dist/cjs/passkey/memory.js +57 -16
- package/dist/cjs/passkey/models.d.ts +13 -4
- package/dist/cjs/passkey/models.js +41 -14
- package/dist/cjs/passkey/sequelize.d.ts +13 -25
- package/dist/cjs/passkey/sequelize.js +68 -153
- package/dist/cjs/passkey/service.d.ts +6 -2
- package/dist/cjs/passkey/service.js +205 -27
- package/dist/cjs/passkey/types.d.ts +18 -9
- package/dist/cjs/sequelize-utils.d.ts +8 -0
- package/dist/cjs/sequelize-utils.js +57 -0
- package/dist/cjs/token/base.d.ts +2 -1
- package/dist/cjs/token/base.js +3 -1
- package/dist/cjs/token/memory.d.ts +10 -0
- package/dist/cjs/token/memory.js +122 -32
- package/dist/cjs/token/sequelize.d.ts +4 -4
- package/dist/cjs/token/sequelize.js +67 -85
- package/dist/cjs/token/types.d.ts +8 -1
- package/dist/cjs/user/base.d.ts +1 -0
- package/dist/cjs/user/base.js +11 -4
- package/dist/cjs/user/memory.d.ts +2 -0
- package/dist/cjs/user/memory.js +9 -10
- package/dist/cjs/user/sequelize.d.ts +7 -2
- package/dist/cjs/user/sequelize.js +19 -32
- package/dist/esm/api-module.d.ts +7 -4
- package/dist/esm/api-module.js +9 -0
- package/dist/esm/api-server-base.d.ts +80 -23
- package/dist/esm/api-server-base.js +608 -100
- package/dist/esm/auth-api/auth-module.d.ts +23 -3
- package/dist/esm/auth-api/auth-module.js +321 -125
- package/dist/esm/auth-api/compat-auth-storage.d.ts +7 -5
- package/dist/esm/auth-api/compat-auth-storage.js +13 -1
- package/dist/esm/auth-api/mem-auth-store.d.ts +5 -3
- package/dist/esm/auth-api/mem-auth-store.js +14 -28
- package/dist/esm/auth-api/module.d.ts +1 -1
- package/dist/esm/auth-api/sql-auth-store.d.ts +16 -4
- package/dist/esm/auth-api/sql-auth-store.js +43 -30
- package/dist/esm/auth-api/storage.d.ts +6 -4
- package/dist/esm/auth-api/storage.js +13 -3
- package/dist/esm/auth-api/types.d.ts +7 -2
- package/dist/esm/auth-api/user-id.d.ts +5 -0
- package/dist/esm/auth-api/user-id.js +32 -0
- package/dist/esm/auth-cookie-options.d.ts +11 -0
- package/dist/esm/auth-cookie-options.js +63 -0
- package/dist/esm/index.d.ts +4 -9
- package/dist/esm/index.js +2 -7
- package/dist/esm/oauth/memory.d.ts +6 -0
- package/dist/esm/oauth/memory.js +44 -11
- package/dist/esm/oauth/models.d.ts +7 -2
- package/dist/esm/oauth/models.js +6 -19
- package/dist/esm/oauth/sequelize.d.ts +10 -48
- package/dist/esm/oauth/sequelize.js +32 -87
- package/dist/esm/oauth/types.d.ts +1 -0
- package/dist/esm/passkey/base.d.ts +2 -0
- package/dist/esm/passkey/config.d.ts +2 -0
- package/dist/esm/passkey/config.js +23 -0
- package/dist/esm/passkey/memory.d.ts +8 -0
- package/dist/esm/passkey/memory.js +57 -16
- package/dist/esm/passkey/models.d.ts +13 -4
- package/dist/esm/passkey/models.js +39 -12
- package/dist/esm/passkey/sequelize.d.ts +13 -25
- package/dist/esm/passkey/sequelize.js +69 -154
- package/dist/esm/passkey/service.d.ts +6 -2
- package/dist/esm/passkey/service.js +173 -28
- package/dist/esm/passkey/types.d.ts +18 -9
- package/dist/esm/sequelize-utils.d.ts +8 -0
- package/dist/esm/sequelize-utils.js +48 -0
- package/dist/esm/token/base.d.ts +2 -1
- package/dist/esm/token/base.js +3 -1
- package/dist/esm/token/memory.d.ts +10 -0
- package/dist/esm/token/memory.js +122 -32
- package/dist/esm/token/sequelize.d.ts +4 -4
- package/dist/esm/token/sequelize.js +67 -85
- package/dist/esm/token/types.d.ts +8 -1
- package/dist/esm/user/base.d.ts +1 -0
- package/dist/esm/user/base.js +11 -4
- package/dist/esm/user/memory.d.ts +2 -0
- package/dist/esm/user/memory.js +9 -10
- package/dist/esm/user/sequelize.d.ts +7 -2
- package/dist/esm/user/sequelize.js +19 -32
- package/docs/swagger/openapi.json +1876 -0
- package/package.json +81 -32
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { PasskeyService } from '../passkey/service.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { AuthAdapter, AuthIdentifier } from './types.js';
|
|
3
3
|
import type { OAuthStore } from '../oauth/base.js';
|
|
4
4
|
import type { AuthCodeData, AuthCodeRequest, OAuthClient } from '../oauth/types.js';
|
|
5
5
|
import type { PasskeyStore } from '../passkey/base.js';
|
|
6
|
-
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyServiceConfig, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
6
|
+
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyServiceConfig, StoredPasskeyCredential, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
7
7
|
import type { TokenStore } from '../token/base.js';
|
|
8
8
|
import type { Token } from '../token/types.js';
|
|
9
9
|
import type { UserStore } from '../user/base.js';
|
|
@@ -11,7 +11,7 @@ interface PasskeyAdapterOptions {
|
|
|
11
11
|
store: PasskeyStore;
|
|
12
12
|
config: PasskeyServiceConfig;
|
|
13
13
|
}
|
|
14
|
-
export interface
|
|
14
|
+
export interface AuthAdapterOptions<UserRow, PublicUser> {
|
|
15
15
|
userStore: UserStore<UserRow, PublicUser>;
|
|
16
16
|
tokenStore: TokenStore;
|
|
17
17
|
passkeys?: PasskeyAdapterOptions | PasskeyService;
|
|
@@ -21,13 +21,13 @@ export interface AuthStorageAdapterOptions<UserRow, PublicUser> {
|
|
|
21
21
|
effectiveUserId: AuthIdentifier;
|
|
22
22
|
}) => boolean | Promise<boolean>;
|
|
23
23
|
}
|
|
24
|
-
export declare class
|
|
24
|
+
export declare class CompositeAuthAdapter<UserRow, PublicUser> implements AuthAdapter<UserRow, PublicUser> {
|
|
25
25
|
private readonly userStore;
|
|
26
26
|
private readonly tokenStore;
|
|
27
27
|
private readonly oauthStore?;
|
|
28
28
|
private readonly passkeyService?;
|
|
29
29
|
private readonly canImpersonateFn?;
|
|
30
|
-
constructor(options:
|
|
30
|
+
constructor(options: AuthAdapterOptions<UserRow, PublicUser>);
|
|
31
31
|
getUser(identifier: AuthIdentifier): Promise<UserRow | null>;
|
|
32
32
|
getUserPasswordHash(user: UserRow): string;
|
|
33
33
|
getUserId(user: UserRow): AuthIdentifier;
|
|
@@ -43,6 +43,8 @@ export declare class AuthStorageAdapter<UserRow, PublicUser> implements AuthStor
|
|
|
43
43
|
}): Promise<boolean>;
|
|
44
44
|
createPasskeyChallenge(params: PasskeyChallengeParams): Promise<PasskeyChallenge>;
|
|
45
45
|
verifyPasskeyResponse(params: PasskeyVerificationParams): Promise<PasskeyVerificationResult>;
|
|
46
|
+
listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
|
|
47
|
+
deletePasskeyCredential(credentialId: Buffer | string): Promise<boolean>;
|
|
46
48
|
getClient(clientId: string): Promise<OAuthClient | null>;
|
|
47
49
|
verifyClientSecret(client: OAuthClient, clientSecret: string | null): Promise<boolean>;
|
|
48
50
|
createAuthCode(request: AuthCodeRequest): Promise<AuthCodeData>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CompositeAuthAdapter = void 0;
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
5
|
const service_js_1 = require("../passkey/service.js");
|
|
6
|
-
class
|
|
6
|
+
class CompositeAuthAdapter {
|
|
7
7
|
constructor(options) {
|
|
8
8
|
this.userStore = options.userStore;
|
|
9
9
|
this.tokenStore = options.tokenStore;
|
|
@@ -55,6 +55,18 @@ class AuthStorageAdapter {
|
|
|
55
55
|
}
|
|
56
56
|
return this.passkeyService.verifyResponse(params);
|
|
57
57
|
}
|
|
58
|
+
async listUserCredentials(userId) {
|
|
59
|
+
if (!this.passkeyService) {
|
|
60
|
+
throw new Error('Passkey storage is not configured');
|
|
61
|
+
}
|
|
62
|
+
return this.passkeyService.listUserCredentials(userId);
|
|
63
|
+
}
|
|
64
|
+
async deletePasskeyCredential(credentialId) {
|
|
65
|
+
if (!this.passkeyService) {
|
|
66
|
+
throw new Error('Passkey storage is not configured');
|
|
67
|
+
}
|
|
68
|
+
return this.passkeyService.deleteCredential(credentialId);
|
|
69
|
+
}
|
|
58
70
|
async getClient(clientId) {
|
|
59
71
|
if (!this.oauthStore) {
|
|
60
72
|
return null;
|
|
@@ -113,4 +125,4 @@ class AuthStorageAdapter {
|
|
|
113
125
|
return params.realUserId === params.effectiveUserId;
|
|
114
126
|
}
|
|
115
127
|
}
|
|
116
|
-
exports.
|
|
128
|
+
exports.CompositeAuthAdapter = CompositeAuthAdapter;
|
|
@@ -2,11 +2,11 @@ import { MemoryOAuthStore } from '../oauth/memory.js';
|
|
|
2
2
|
import { MemoryPasskeyStore } from '../passkey/memory.js';
|
|
3
3
|
import { TokenStore } from '../token/base.js';
|
|
4
4
|
import { MemoryUserStore } from '../user/memory.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { AuthAdapter, AuthIdentifier } from './types.js';
|
|
6
6
|
import type { MemoryOAuthStoreOptions } from '../oauth/memory.js';
|
|
7
7
|
import type { AuthCodeData, AuthCodeRequest, OAuthClient } from '../oauth/types.js';
|
|
8
8
|
import type { MemoryPasskeyStoreOptions } from '../passkey/memory.js';
|
|
9
|
-
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyServiceConfig, PasskeyUserDescriptor, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
9
|
+
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyServiceConfig, PasskeyUserDescriptor, StoredPasskeyCredential, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
10
10
|
import type { Token } from '../token/types.js';
|
|
11
11
|
import type { MemoryUserAttributes, MemoryPublicUser, MemoryUserStoreOptions } from '../user/memory.js';
|
|
12
12
|
interface PasskeyOptions extends Partial<PasskeyServiceConfig> {
|
|
@@ -24,7 +24,7 @@ export interface MemAuthStoreParams<UserAttributes extends MemoryUserAttributes
|
|
|
24
24
|
}) => boolean | Promise<boolean>;
|
|
25
25
|
tokenStore?: TokenStore;
|
|
26
26
|
}
|
|
27
|
-
export declare class MemAuthStore<UserAttributes extends MemoryUserAttributes = MemoryUserAttributes, PublicUserShape extends MemoryPublicUser<UserAttributes> = MemoryPublicUser<UserAttributes>> implements
|
|
27
|
+
export declare class MemAuthStore<UserAttributes extends MemoryUserAttributes = MemoryUserAttributes, PublicUserShape extends MemoryPublicUser<UserAttributes> = MemoryPublicUser<UserAttributes>> implements AuthAdapter<UserAttributes, PublicUserShape> {
|
|
28
28
|
readonly userStore: MemoryUserStore<UserAttributes, PublicUserShape>;
|
|
29
29
|
readonly tokenStore: TokenStore;
|
|
30
30
|
readonly passkeyStore?: MemoryPasskeyStore;
|
|
@@ -54,6 +54,8 @@ export declare class MemAuthStore<UserAttributes extends MemoryUserAttributes =
|
|
|
54
54
|
}): Promise<boolean>;
|
|
55
55
|
createPasskeyChallenge(params: PasskeyChallengeParams): Promise<PasskeyChallenge>;
|
|
56
56
|
verifyPasskeyResponse(params: PasskeyVerificationParams): Promise<PasskeyVerificationResult>;
|
|
57
|
+
listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
|
|
58
|
+
deletePasskeyCredential(credentialId: Buffer | string): Promise<boolean>;
|
|
57
59
|
getClient(clientId: string): Promise<OAuthClient | null>;
|
|
58
60
|
verifyClientSecret(client: OAuthClient, clientSecret: string | null): Promise<boolean>;
|
|
59
61
|
createAuthCode(request: AuthCodeRequest): Promise<AuthCodeData>;
|
|
@@ -2,32 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MemAuthStore = void 0;
|
|
4
4
|
const memory_js_1 = require("../oauth/memory.js");
|
|
5
|
+
const config_js_1 = require("../passkey/config.js");
|
|
5
6
|
const memory_js_2 = require("../passkey/memory.js");
|
|
6
7
|
const memory_js_3 = require("../token/memory.js");
|
|
7
8
|
const memory_js_4 = require("../user/memory.js");
|
|
8
9
|
const compat_auth_storage_js_1 = require("./compat-auth-storage.js");
|
|
9
|
-
const
|
|
10
|
-
rpId: 'localhost',
|
|
11
|
-
rpName: 'API Server',
|
|
12
|
-
origins: ['http://localhost:5173'],
|
|
13
|
-
timeoutMs: 5 * 60 * 1000,
|
|
14
|
-
userVerification: 'preferred'
|
|
15
|
-
};
|
|
16
|
-
function isOriginString(origin) {
|
|
17
|
-
return typeof origin === 'string' && origin.trim().length > 0;
|
|
18
|
-
}
|
|
19
|
-
function normalizePasskeyConfig(config = {}) {
|
|
20
|
-
const candidateOrigins = Array.isArray(config.origins) && config.origins.length > 0 ? config.origins.filter(isOriginString) : null;
|
|
21
|
-
return {
|
|
22
|
-
rpId: config.rpId?.trim() || DEFAULT_PASSKEY_CONFIG.rpId,
|
|
23
|
-
rpName: config.rpName?.trim() || DEFAULT_PASSKEY_CONFIG.rpName,
|
|
24
|
-
origins: candidateOrigins ? candidateOrigins.map((origin) => origin.trim()) : DEFAULT_PASSKEY_CONFIG.origins,
|
|
25
|
-
timeoutMs: typeof config.timeoutMs === 'number' && config.timeoutMs > 0
|
|
26
|
-
? config.timeoutMs
|
|
27
|
-
: DEFAULT_PASSKEY_CONFIG.timeoutMs,
|
|
28
|
-
userVerification: config.userVerification ?? DEFAULT_PASSKEY_CONFIG.userVerification
|
|
29
|
-
};
|
|
30
|
-
}
|
|
10
|
+
const user_id_js_1 = require("./user-id.js");
|
|
31
11
|
class MemAuthStore {
|
|
32
12
|
constructor(params = {}) {
|
|
33
13
|
this.userStore = new memory_js_4.MemoryUserStore({
|
|
@@ -42,7 +22,7 @@ class MemAuthStore {
|
|
|
42
22
|
let passkeyStore;
|
|
43
23
|
let passkeyConfig;
|
|
44
24
|
if (params.passkeys !== false) {
|
|
45
|
-
passkeyConfig = normalizePasskeyConfig(params.passkeys ?? {});
|
|
25
|
+
passkeyConfig = (0, config_js_1.normalizePasskeyConfig)(params.passkeys ?? {});
|
|
46
26
|
const resolveUser = async (lookup) => {
|
|
47
27
|
const found = await this.userStore.findUser(lookup.userId ?? lookup.login ?? '');
|
|
48
28
|
if (!found) {
|
|
@@ -59,7 +39,7 @@ class MemAuthStore {
|
|
|
59
39
|
passkeyStore = new memory_js_2.MemoryPasskeyStore({ resolveUser });
|
|
60
40
|
this.passkeyStore = passkeyStore;
|
|
61
41
|
}
|
|
62
|
-
this.adapter = new compat_auth_storage_js_1.
|
|
42
|
+
this.adapter = new compat_auth_storage_js_1.CompositeAuthAdapter({
|
|
63
43
|
userStore: this.userStore,
|
|
64
44
|
tokenStore: this.tokenStore,
|
|
65
45
|
passkeys: passkeyStore && passkeyConfig ? { store: passkeyStore, config: passkeyConfig } : undefined,
|
|
@@ -94,16 +74,16 @@ class MemAuthStore {
|
|
|
94
74
|
async getToken(query, opts) {
|
|
95
75
|
const normalized = {
|
|
96
76
|
...query,
|
|
97
|
-
userId:
|
|
98
|
-
ruid:
|
|
77
|
+
userId: (0, user_id_js_1.toOptionalStringId)(query.userId),
|
|
78
|
+
ruid: (0, user_id_js_1.toOptionalStringId)(query.ruid)
|
|
99
79
|
};
|
|
100
80
|
return this.adapter.getToken(normalized, opts);
|
|
101
81
|
}
|
|
102
82
|
async deleteToken(query) {
|
|
103
83
|
const normalized = {
|
|
104
84
|
...query,
|
|
105
|
-
userId:
|
|
106
|
-
ruid:
|
|
85
|
+
userId: (0, user_id_js_1.toOptionalStringId)(query.userId),
|
|
86
|
+
ruid: (0, user_id_js_1.toOptionalStringId)(query.ruid)
|
|
107
87
|
};
|
|
108
88
|
return this.adapter.deleteToken(normalized);
|
|
109
89
|
}
|
|
@@ -116,6 +96,12 @@ class MemAuthStore {
|
|
|
116
96
|
async verifyPasskeyResponse(params) {
|
|
117
97
|
return this.adapter.verifyPasskeyResponse(params);
|
|
118
98
|
}
|
|
99
|
+
async listUserCredentials(userId) {
|
|
100
|
+
return this.adapter.listUserCredentials(userId);
|
|
101
|
+
}
|
|
102
|
+
async deletePasskeyCredential(credentialId) {
|
|
103
|
+
return this.adapter.deletePasskeyCredential(credentialId);
|
|
104
|
+
}
|
|
119
105
|
async getClient(clientId) {
|
|
120
106
|
return this.adapter.getClient(clientId);
|
|
121
107
|
}
|
|
@@ -8,7 +8,7 @@ export interface AuthProviderModule<UserRow = unknown> {
|
|
|
8
8
|
expires?: Date;
|
|
9
9
|
}): Promise<TokenPair>;
|
|
10
10
|
}
|
|
11
|
-
export declare abstract class BaseAuthModule<UserRow = unknown> extends ApiModule
|
|
11
|
+
export declare abstract class BaseAuthModule<UserRow = unknown> extends ApiModule implements AuthProviderModule<UserRow> {
|
|
12
12
|
readonly moduleType: "auth";
|
|
13
13
|
protected constructor(opts: {
|
|
14
14
|
namespace: string;
|
|
@@ -3,21 +3,31 @@ import { SequelizeOAuthStore, type SequelizeOAuthStoreOptions } from '../oauth/s
|
|
|
3
3
|
import { SequelizePasskeyStore } from '../passkey/sequelize.js';
|
|
4
4
|
import { type SequelizeTokenStoreOptions } from '../token/sequelize.js';
|
|
5
5
|
import { SequelizeUserStore, type AuthUserAttributes, GenericUserModel, GenericUserModelStatic } from '../user/sequelize.js';
|
|
6
|
-
import type {
|
|
6
|
+
import type { AuthAdapter, AuthIdentifier } from './types.js';
|
|
7
7
|
import type { AuthCodeData, AuthCodeRequest, OAuthClient } from '../oauth/types.js';
|
|
8
|
-
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyServiceConfig, PasskeyUserDescriptor, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
8
|
+
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyServiceConfig, PasskeyUserDescriptor, StoredPasskeyCredential, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
9
9
|
import type { TokenStore } from '../token/base.js';
|
|
10
10
|
import type { Token } from '../token/types.js';
|
|
11
11
|
interface PasskeyOptions extends Partial<PasskeyServiceConfig> {
|
|
12
12
|
enabled?: boolean;
|
|
13
13
|
}
|
|
14
|
+
export interface SqlAuthStoreTablePrefixes {
|
|
15
|
+
user?: string;
|
|
16
|
+
token?: string;
|
|
17
|
+
passkey?: string;
|
|
18
|
+
oauth?: string;
|
|
19
|
+
}
|
|
14
20
|
export interface SqlAuthStoreParams<UserAttributes extends AuthUserAttributes = AuthUserAttributes, PublicUserShape extends Omit<UserAttributes, 'password'> = Omit<UserAttributes, 'password'>> {
|
|
15
21
|
sequelize: Sequelize;
|
|
16
22
|
syncOptions?: SyncOptions;
|
|
17
23
|
bcryptRounds?: number;
|
|
18
24
|
passwordPepper?: string;
|
|
25
|
+
tablePrefix?: string;
|
|
26
|
+
tablePrefixes?: SqlAuthStoreTablePrefixes;
|
|
19
27
|
userModel?: GenericUserModelStatic;
|
|
20
|
-
userModelFactory?: (sequelize: Sequelize
|
|
28
|
+
userModelFactory?: (sequelize: Sequelize, options?: {
|
|
29
|
+
tablePrefix?: string;
|
|
30
|
+
}) => GenericUserModelStatic;
|
|
21
31
|
userRecordMapper?: (model: GenericUserModel) => UserAttributes;
|
|
22
32
|
publicUserMapper?: (user: UserAttributes) => PublicUserShape;
|
|
23
33
|
passkeyUserMapper?: (user: UserAttributes) => PasskeyUserDescriptor;
|
|
@@ -30,7 +40,7 @@ export interface SqlAuthStoreParams<UserAttributes extends AuthUserAttributes =
|
|
|
30
40
|
tokenStoreOptions?: Omit<SequelizeTokenStoreOptions, 'sequelize'>;
|
|
31
41
|
oauthStoreOptions?: Omit<SequelizeOAuthStoreOptions, 'sequelize'>;
|
|
32
42
|
}
|
|
33
|
-
export declare class SqlAuthStore<UserAttributes extends AuthUserAttributes = AuthUserAttributes, PublicUserShape extends Omit<UserAttributes, 'password'> = Omit<UserAttributes, 'password'>> implements
|
|
43
|
+
export declare class SqlAuthStore<UserAttributes extends AuthUserAttributes = AuthUserAttributes, PublicUserShape extends Omit<UserAttributes, 'password'> = Omit<UserAttributes, 'password'>> implements AuthAdapter<UserAttributes, PublicUserShape> {
|
|
34
44
|
readonly userStore: SequelizeUserStore<UserAttributes, PublicUserShape>;
|
|
35
45
|
readonly tokenStore: TokenStore;
|
|
36
46
|
readonly passkeyStore?: SequelizePasskeyStore;
|
|
@@ -63,6 +73,8 @@ export declare class SqlAuthStore<UserAttributes extends AuthUserAttributes = Au
|
|
|
63
73
|
}): Promise<boolean>;
|
|
64
74
|
createPasskeyChallenge(params: PasskeyChallengeParams): Promise<PasskeyChallenge>;
|
|
65
75
|
verifyPasskeyResponse(params: PasskeyVerificationParams): Promise<PasskeyVerificationResult>;
|
|
76
|
+
listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
|
|
77
|
+
deletePasskeyCredential(credentialId: Buffer | string): Promise<boolean>;
|
|
66
78
|
getClient(clientId: string): Promise<OAuthClient | null>;
|
|
67
79
|
verifyClientSecret(client: OAuthClient, clientSecret: string | null): Promise<boolean>;
|
|
68
80
|
createAuthCode(request: AuthCodeRequest): Promise<AuthCodeData>;
|
|
@@ -2,31 +2,21 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SqlAuthStore = void 0;
|
|
4
4
|
const sequelize_js_1 = require("../oauth/sequelize.js");
|
|
5
|
+
const config_js_1 = require("../passkey/config.js");
|
|
5
6
|
const sequelize_js_2 = require("../passkey/sequelize.js");
|
|
7
|
+
const sequelize_utils_js_1 = require("../sequelize-utils.js");
|
|
6
8
|
const sequelize_js_3 = require("../token/sequelize.js");
|
|
7
9
|
const sequelize_js_4 = require("../user/sequelize.js");
|
|
8
10
|
const compat_auth_storage_js_1 = require("./compat-auth-storage.js");
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
function normalizePasskeyConfig(config = {}) {
|
|
20
|
-
const candidateOrigins = Array.isArray(config.origins) && config.origins.length > 0 ? config.origins.filter(isOriginString) : null;
|
|
21
|
-
return {
|
|
22
|
-
rpId: config.rpId?.trim() || DEFAULT_PASSKEY_CONFIG.rpId,
|
|
23
|
-
rpName: config.rpName?.trim() || DEFAULT_PASSKEY_CONFIG.rpName,
|
|
24
|
-
origins: candidateOrigins ? candidateOrigins.map((origin) => origin.trim()) : DEFAULT_PASSKEY_CONFIG.origins,
|
|
25
|
-
timeoutMs: typeof config.timeoutMs === 'number' && config.timeoutMs > 0
|
|
26
|
-
? config.timeoutMs
|
|
27
|
-
: DEFAULT_PASSKEY_CONFIG.timeoutMs,
|
|
28
|
-
userVerification: config.userVerification ?? DEFAULT_PASSKEY_CONFIG.userVerification
|
|
29
|
-
};
|
|
11
|
+
const user_id_js_1 = require("./user-id.js");
|
|
12
|
+
function resolveTablePrefix(...prefixes) {
|
|
13
|
+
for (const prefix of prefixes) {
|
|
14
|
+
const normalized = (0, sequelize_utils_js_1.normalizeTablePrefix)(prefix);
|
|
15
|
+
if (normalized) {
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
30
20
|
}
|
|
31
21
|
class SqlAuthStore {
|
|
32
22
|
constructor(params) {
|
|
@@ -36,6 +26,8 @@ class SqlAuthStore {
|
|
|
36
26
|
}
|
|
37
27
|
this.sequelize = params.sequelize;
|
|
38
28
|
this.syncOptions = params.syncOptions;
|
|
29
|
+
const moduleTablePrefixes = params.tablePrefixes ?? {};
|
|
30
|
+
const userTablePrefix = resolveTablePrefix(moduleTablePrefixes.user, params.tablePrefix);
|
|
39
31
|
this.userStore = new sequelize_js_4.SequelizeUserStore({
|
|
40
32
|
sequelize: this.sequelize,
|
|
41
33
|
userModel: params.userModel,
|
|
@@ -43,19 +35,29 @@ class SqlAuthStore {
|
|
|
43
35
|
recordMapper: params.userRecordMapper,
|
|
44
36
|
toPublic: params.publicUserMapper,
|
|
45
37
|
bcryptRounds: params.bcryptRounds,
|
|
46
|
-
bcryptPepper: params.passwordPepper
|
|
38
|
+
bcryptPepper: params.passwordPepper,
|
|
39
|
+
tablePrefix: userTablePrefix
|
|
47
40
|
});
|
|
41
|
+
const tokenTablePrefix = resolveTablePrefix(params.tokenStoreOptions?.tablePrefix, moduleTablePrefixes.token, params.tablePrefix);
|
|
48
42
|
this.tokenStore =
|
|
49
|
-
params.tokenStore ??
|
|
43
|
+
params.tokenStore ??
|
|
44
|
+
new sequelize_js_3.SequelizeTokenStore({
|
|
45
|
+
sequelize: this.sequelize,
|
|
46
|
+
...params.tokenStoreOptions,
|
|
47
|
+
tablePrefix: tokenTablePrefix
|
|
48
|
+
});
|
|
49
|
+
const oauthTablePrefix = resolveTablePrefix(params.oauthStoreOptions?.tablePrefix, moduleTablePrefixes.oauth, params.tablePrefix);
|
|
50
50
|
this.oauthStore = new sequelize_js_1.SequelizeOAuthStore({
|
|
51
51
|
sequelize: this.sequelize,
|
|
52
52
|
...params.oauthStoreOptions,
|
|
53
|
+
tablePrefix: oauthTablePrefix,
|
|
53
54
|
bcryptRounds: params.bcryptRounds
|
|
54
55
|
});
|
|
55
56
|
let passkeyStore;
|
|
56
57
|
let passkeyConfig;
|
|
57
58
|
if (params.passkeys !== false) {
|
|
58
|
-
|
|
59
|
+
const passkeyTablePrefix = resolveTablePrefix(moduleTablePrefixes.passkey, params.tablePrefix);
|
|
60
|
+
passkeyConfig = (0, config_js_1.normalizePasskeyConfig)(params.passkeys ?? {});
|
|
59
61
|
const resolveUser = async (lookup) => {
|
|
60
62
|
const found = await this.userStore.findUser(lookup.userId ?? lookup.login ?? '');
|
|
61
63
|
if (!found) {
|
|
@@ -69,10 +71,14 @@ class SqlAuthStore {
|
|
|
69
71
|
}));
|
|
70
72
|
return mapper(found);
|
|
71
73
|
};
|
|
72
|
-
passkeyStore = new sequelize_js_2.SequelizePasskeyStore({
|
|
74
|
+
passkeyStore = new sequelize_js_2.SequelizePasskeyStore({
|
|
75
|
+
sequelize: this.sequelize,
|
|
76
|
+
resolveUser,
|
|
77
|
+
tablePrefix: passkeyTablePrefix
|
|
78
|
+
});
|
|
73
79
|
this.passkeyStore = passkeyStore;
|
|
74
80
|
}
|
|
75
|
-
this.adapter = new compat_auth_storage_js_1.
|
|
81
|
+
this.adapter = new compat_auth_storage_js_1.CompositeAuthAdapter({
|
|
76
82
|
userStore: this.userStore,
|
|
77
83
|
tokenStore: this.tokenStore,
|
|
78
84
|
passkeys: passkeyStore && passkeyConfig ? { store: passkeyStore, config: passkeyConfig } : undefined,
|
|
@@ -101,6 +107,7 @@ class SqlAuthStore {
|
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
finally {
|
|
110
|
+
// Prevent double-close errors when the same Sequelize instance is shared with other code.
|
|
104
111
|
this.sequelize.close = async () => { };
|
|
105
112
|
}
|
|
106
113
|
}
|
|
@@ -125,16 +132,16 @@ class SqlAuthStore {
|
|
|
125
132
|
async getToken(query, opts) {
|
|
126
133
|
const normalized = {
|
|
127
134
|
...query,
|
|
128
|
-
userId:
|
|
129
|
-
ruid:
|
|
135
|
+
userId: (0, user_id_js_1.toOptionalStringId)(query.userId),
|
|
136
|
+
ruid: (0, user_id_js_1.toOptionalStringId)(query.ruid)
|
|
130
137
|
};
|
|
131
138
|
return this.adapter.getToken(normalized, opts);
|
|
132
139
|
}
|
|
133
140
|
async deleteToken(query) {
|
|
134
141
|
const normalized = {
|
|
135
142
|
...query,
|
|
136
|
-
userId:
|
|
137
|
-
ruid:
|
|
143
|
+
userId: (0, user_id_js_1.toOptionalStringId)(query.userId),
|
|
144
|
+
ruid: (0, user_id_js_1.toOptionalStringId)(query.ruid)
|
|
138
145
|
};
|
|
139
146
|
return this.adapter.deleteToken(normalized);
|
|
140
147
|
}
|
|
@@ -147,6 +154,12 @@ class SqlAuthStore {
|
|
|
147
154
|
async verifyPasskeyResponse(params) {
|
|
148
155
|
return this.adapter.verifyPasskeyResponse(params);
|
|
149
156
|
}
|
|
157
|
+
async listUserCredentials(userId) {
|
|
158
|
+
return this.adapter.listUserCredentials(userId);
|
|
159
|
+
}
|
|
160
|
+
async deletePasskeyCredential(credentialId) {
|
|
161
|
+
return this.adapter.deletePasskeyCredential(credentialId);
|
|
162
|
+
}
|
|
150
163
|
async getClient(clientId) {
|
|
151
164
|
return this.adapter.getClient(clientId);
|
|
152
165
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AuthAdapter, AuthIdentifier } from './types.js';
|
|
2
2
|
import type { AuthCodeData, AuthCodeRequest, OAuthClient } from '../oauth/types.js';
|
|
3
|
-
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
3
|
+
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyVerificationParams, PasskeyVerificationResult, StoredPasskeyCredential } from '../passkey/types.js';
|
|
4
4
|
import type { Token } from '../token/types.js';
|
|
5
|
-
export declare class
|
|
5
|
+
export declare class BaseAuthAdapter<UserRow = unknown, SafeUser = unknown> implements AuthAdapter<UserRow, SafeUser> {
|
|
6
6
|
getUser(identifier: AuthIdentifier): Promise<UserRow | null>;
|
|
7
7
|
getUserPasswordHash(user: UserRow): string;
|
|
8
8
|
getUserId(user: UserRow): AuthIdentifier;
|
|
@@ -24,6 +24,8 @@ export declare class BaseAuthStorage<UserRow = unknown, SafeUser = unknown> impl
|
|
|
24
24
|
}): Promise<boolean>;
|
|
25
25
|
createPasskeyChallenge(params: PasskeyChallengeParams): Promise<PasskeyChallenge>;
|
|
26
26
|
verifyPasskeyResponse(params: PasskeyVerificationParams): Promise<PasskeyVerificationResult>;
|
|
27
|
+
listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
|
|
28
|
+
deletePasskeyCredential(credentialId: Buffer | string): Promise<boolean>;
|
|
27
29
|
getClient(clientId: string): Promise<OAuthClient | null>;
|
|
28
30
|
verifyClientSecret(client: OAuthClient, clientSecret: string | null): Promise<boolean>;
|
|
29
31
|
createAuthCode(request: AuthCodeRequest): Promise<AuthCodeData>;
|
|
@@ -33,4 +35,4 @@ export declare class BaseAuthStorage<UserRow = unknown, SafeUser = unknown> impl
|
|
|
33
35
|
effectiveUserId: AuthIdentifier;
|
|
34
36
|
}): Promise<boolean>;
|
|
35
37
|
}
|
|
36
|
-
export declare const
|
|
38
|
+
export declare const nullAuthAdapter: AuthAdapter<unknown, unknown>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
// Handy base you can extend when wiring a real
|
|
3
|
+
exports.nullAuthAdapter = exports.BaseAuthAdapter = void 0;
|
|
4
|
+
// Handy base you can extend when wiring a real auth adapter. Every method
|
|
5
5
|
// throws by default so unimplemented hooks fail loudly.
|
|
6
|
-
class
|
|
6
|
+
class BaseAuthAdapter {
|
|
7
7
|
// Override to load a user record by identifier
|
|
8
8
|
async getUser(identifier) {
|
|
9
9
|
void identifier;
|
|
@@ -60,6 +60,16 @@ class BaseAuthStorage {
|
|
|
60
60
|
void params;
|
|
61
61
|
throw new Error('Auth storage not configured');
|
|
62
62
|
}
|
|
63
|
+
// Override to list passkey credentials for a user
|
|
64
|
+
async listUserCredentials(userId) {
|
|
65
|
+
void userId;
|
|
66
|
+
throw new Error('Auth storage not configured');
|
|
67
|
+
}
|
|
68
|
+
// Override to delete a passkey credential
|
|
69
|
+
async deletePasskeyCredential(credentialId) {
|
|
70
|
+
void credentialId;
|
|
71
|
+
throw new Error('Auth storage not configured');
|
|
72
|
+
}
|
|
63
73
|
// Override to fetch an OAuth client by identifier
|
|
64
74
|
async getClient(clientId) {
|
|
65
75
|
void clientId;
|
|
@@ -88,5 +98,5 @@ class BaseAuthStorage {
|
|
|
88
98
|
return false;
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
|
-
exports.
|
|
92
|
-
exports.
|
|
101
|
+
exports.BaseAuthAdapter = BaseAuthAdapter;
|
|
102
|
+
exports.nullAuthAdapter = new BaseAuthAdapter();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { AuthCodeData, AuthCodeRequest, OAuthClient } from '../oauth/types.js';
|
|
2
|
-
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyVerificationParams, PasskeyVerificationResult } from '../passkey/types.js';
|
|
2
|
+
import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyVerificationParams, PasskeyVerificationResult, StoredPasskeyCredential } from '../passkey/types.js';
|
|
3
3
|
import type { Token } from '../token/types.js';
|
|
4
4
|
export type AuthIdentifier = string | number;
|
|
5
|
-
|
|
5
|
+
/** @internal */
|
|
6
|
+
export interface AuthAdapter<UserRow, SafeUser> {
|
|
6
7
|
getUser(identifier: AuthIdentifier): Promise<UserRow | null>;
|
|
7
8
|
getUserPasswordHash(user: UserRow): string;
|
|
8
9
|
getUserId(user: UserRow): AuthIdentifier;
|
|
@@ -18,6 +19,8 @@ export interface AuthStorage<UserRow, SafeUser> {
|
|
|
18
19
|
}): Promise<boolean>;
|
|
19
20
|
createPasskeyChallenge?(params: PasskeyChallengeParams): Promise<PasskeyChallenge>;
|
|
20
21
|
verifyPasskeyResponse?(params: PasskeyVerificationParams): Promise<PasskeyVerificationResult>;
|
|
22
|
+
listUserCredentials?(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
|
|
23
|
+
deletePasskeyCredential?(credentialId: Buffer | string): Promise<boolean>;
|
|
21
24
|
getClient?(clientId: string): Promise<OAuthClient | null>;
|
|
22
25
|
verifyClientSecret?(client: OAuthClient, clientSecret: string | null): Promise<boolean>;
|
|
23
26
|
createAuthCode?(request: AuthCodeRequest): Promise<AuthCodeData>;
|
|
@@ -27,3 +30,5 @@ export interface AuthStorage<UserRow, SafeUser> {
|
|
|
27
30
|
effectiveUserId: AuthIdentifier;
|
|
28
31
|
}): Promise<boolean>;
|
|
29
32
|
}
|
|
33
|
+
/** @internal */
|
|
34
|
+
export type AuthStorage<UserRow, SafeUser> = AuthAdapter<UserRow, SafeUser>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AuthIdentifier } from './types.js';
|
|
2
|
+
export declare function normalizeComparableUserId(identifier: AuthIdentifier): string;
|
|
3
|
+
export declare function normalizeNumericUserId(identifier: AuthIdentifier): number;
|
|
4
|
+
export declare function normalizeStringUserId(identifier: AuthIdentifier): string;
|
|
5
|
+
export declare function toOptionalStringId(value: AuthIdentifier | undefined | null): string | undefined;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeComparableUserId = normalizeComparableUserId;
|
|
4
|
+
exports.normalizeNumericUserId = normalizeNumericUserId;
|
|
5
|
+
exports.normalizeStringUserId = normalizeStringUserId;
|
|
6
|
+
exports.toOptionalStringId = toOptionalStringId;
|
|
7
|
+
function normalizeComparableUserId(identifier) {
|
|
8
|
+
if (typeof identifier === 'number' && Number.isFinite(identifier)) {
|
|
9
|
+
return String(identifier);
|
|
10
|
+
}
|
|
11
|
+
if (typeof identifier === 'string') {
|
|
12
|
+
const trimmed = identifier.trim();
|
|
13
|
+
if (trimmed.length === 0) {
|
|
14
|
+
throw new Error(`Unable to normalise user identifier: ${identifier}`);
|
|
15
|
+
}
|
|
16
|
+
if (/^\d+$/.test(trimmed)) {
|
|
17
|
+
return String(Number(trimmed));
|
|
18
|
+
}
|
|
19
|
+
return trimmed;
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Unable to normalise user identifier: ${identifier}`);
|
|
22
|
+
}
|
|
23
|
+
function normalizeNumericUserId(identifier) {
|
|
24
|
+
const normalized = normalizeComparableUserId(identifier);
|
|
25
|
+
if (/^\d+$/.test(normalized)) {
|
|
26
|
+
return Number(normalized);
|
|
27
|
+
}
|
|
28
|
+
throw new Error(`Unable to normalise user identifier: ${identifier}`);
|
|
29
|
+
}
|
|
30
|
+
function normalizeStringUserId(identifier) {
|
|
31
|
+
return normalizeComparableUserId(identifier);
|
|
32
|
+
}
|
|
33
|
+
function toOptionalStringId(value) {
|
|
34
|
+
if (value === undefined || value === null) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
return String(value);
|
|
38
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Request } from 'express';
|
|
2
|
+
import type { CookieOptions } from 'express-serve-static-core';
|
|
3
|
+
export interface AuthCookieConfig {
|
|
4
|
+
cookieSecure?: boolean | 'auto';
|
|
5
|
+
cookieSameSite?: 'lax' | 'strict' | 'none';
|
|
6
|
+
cookieHttpOnly?: boolean;
|
|
7
|
+
cookieDomain?: string;
|
|
8
|
+
cookiePath?: string;
|
|
9
|
+
devMode?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function buildAuthCookieOptions(config: AuthCookieConfig, req: Pick<Request, 'headers' | 'protocol'>): CookieOptions;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAuthCookieOptions = buildAuthCookieOptions;
|
|
4
|
+
function firstHeaderValue(value) {
|
|
5
|
+
if (typeof value === 'string') {
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
if (Array.isArray(value)) {
|
|
9
|
+
return value[0] ?? '';
|
|
10
|
+
}
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
13
|
+
function resolveOriginHostname(origin) {
|
|
14
|
+
try {
|
|
15
|
+
const url = new URL(origin);
|
|
16
|
+
const hostname = url.hostname.trim().toLowerCase();
|
|
17
|
+
return hostname.length > 0 ? hostname : null;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function isLocalhostOrigin(origin) {
|
|
24
|
+
const hostname = resolveOriginHostname(origin);
|
|
25
|
+
if (!hostname) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return hostname === 'localhost' || hostname.endsWith('.localhost');
|
|
29
|
+
}
|
|
30
|
+
function buildAuthCookieOptions(config, req) {
|
|
31
|
+
const forwardedProto = firstHeaderValue(req.headers['x-forwarded-proto']).split(',')[0].trim().toLowerCase();
|
|
32
|
+
const isHttps = forwardedProto === 'https' || req.protocol === 'https';
|
|
33
|
+
const origin = firstHeaderValue(req.headers.origin ?? req.headers.referer);
|
|
34
|
+
let secure;
|
|
35
|
+
if (config.cookieSecure === true) {
|
|
36
|
+
secure = true;
|
|
37
|
+
}
|
|
38
|
+
else if (config.cookieSecure === false) {
|
|
39
|
+
secure = false;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
secure = isHttps;
|
|
43
|
+
}
|
|
44
|
+
let sameSite = config.cookieSameSite ?? 'lax';
|
|
45
|
+
if (sameSite !== 'lax' && sameSite !== 'strict' && sameSite !== 'none') {
|
|
46
|
+
sameSite = 'lax';
|
|
47
|
+
}
|
|
48
|
+
let resolvedSecure = secure;
|
|
49
|
+
if (sameSite === 'none' && resolvedSecure !== true) {
|
|
50
|
+
// Modern browsers reject SameSite=None cookies unless Secure is set.
|
|
51
|
+
resolvedSecure = true;
|
|
52
|
+
}
|
|
53
|
+
const options = {
|
|
54
|
+
httpOnly: config.cookieHttpOnly ?? true,
|
|
55
|
+
secure: resolvedSecure,
|
|
56
|
+
sameSite,
|
|
57
|
+
domain: config.cookieDomain || undefined,
|
|
58
|
+
path: config.cookiePath || '/',
|
|
59
|
+
maxAge: undefined
|
|
60
|
+
};
|
|
61
|
+
if (config.devMode && isLocalhostOrigin(origin)) {
|
|
62
|
+
// Domain cookies do not work on localhost; avoid breaking local development when cookieDomain is set.
|
|
63
|
+
options.domain = undefined;
|
|
64
|
+
}
|
|
65
|
+
return options;
|
|
66
|
+
}
|