@joethebigbuddy/auth 0.0.1
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.md +97 -0
- package/dist/express.d.ts +2 -0
- package/dist/express.d.ts.map +1 -0
- package/dist/express.js +2 -0
- package/dist/express.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/adapters/express/express-auth-adapter.d.ts +48 -0
- package/dist/lib/adapters/express/express-auth-adapter.d.ts.map +1 -0
- package/dist/lib/adapters/express/express-auth-adapter.js +161 -0
- package/dist/lib/adapters/express/express-auth-adapter.js.map +1 -0
- package/dist/lib/adapters/logging/create-logging-adapter.d.ts +4 -0
- package/dist/lib/adapters/logging/create-logging-adapter.d.ts.map +1 -0
- package/dist/lib/adapters/logging/create-logging-adapter.js +20 -0
- package/dist/lib/adapters/logging/create-logging-adapter.js.map +1 -0
- package/dist/lib/adapters/memory/memory-refresh-token-store.d.ts +10 -0
- package/dist/lib/adapters/memory/memory-refresh-token-store.d.ts.map +1 -0
- package/dist/lib/adapters/memory/memory-refresh-token-store.js +34 -0
- package/dist/lib/adapters/memory/memory-refresh-token-store.js.map +1 -0
- package/dist/lib/adapters/memory/memory-session-store.d.ts +12 -0
- package/dist/lib/adapters/memory/memory-session-store.d.ts.map +1 -0
- package/dist/lib/adapters/memory/memory-session-store.js +32 -0
- package/dist/lib/adapters/memory/memory-session-store.js.map +1 -0
- package/dist/lib/adapters/postgres/create-postgres-auth-storage.d.ts +16 -0
- package/dist/lib/adapters/postgres/create-postgres-auth-storage.d.ts.map +1 -0
- package/dist/lib/adapters/postgres/create-postgres-auth-storage.js +18 -0
- package/dist/lib/adapters/postgres/create-postgres-auth-storage.js.map +1 -0
- package/dist/lib/adapters/postgres/postgres-refresh-token-store.d.ts +13 -0
- package/dist/lib/adapters/postgres/postgres-refresh-token-store.d.ts.map +1 -0
- package/dist/lib/adapters/postgres/postgres-refresh-token-store.js +63 -0
- package/dist/lib/adapters/postgres/postgres-refresh-token-store.js.map +1 -0
- package/dist/lib/adapters/postgres/postgres-session-store.d.ts +15 -0
- package/dist/lib/adapters/postgres/postgres-session-store.d.ts.map +1 -0
- package/dist/lib/adapters/postgres/postgres-session-store.js +75 -0
- package/dist/lib/adapters/postgres/postgres-session-store.js.map +1 -0
- package/dist/lib/adapters/postgres/shared.d.ts +41 -0
- package/dist/lib/adapters/postgres/shared.d.ts.map +1 -0
- package/dist/lib/adapters/postgres/shared.js +83 -0
- package/dist/lib/adapters/postgres/shared.js.map +1 -0
- package/dist/lib/adapters/redis/create-redis-auth-storage.d.ts +2329 -0
- package/dist/lib/adapters/redis/create-redis-auth-storage.d.ts.map +1 -0
- package/dist/lib/adapters/redis/create-redis-auth-storage.js +25 -0
- package/dist/lib/adapters/redis/create-redis-auth-storage.js.map +1 -0
- package/dist/lib/adapters/redis/redis-refresh-token-store.d.ts +13 -0
- package/dist/lib/adapters/redis/redis-refresh-token-store.d.ts.map +1 -0
- package/dist/lib/adapters/redis/redis-refresh-token-store.js +46 -0
- package/dist/lib/adapters/redis/redis-refresh-token-store.js.map +1 -0
- package/dist/lib/adapters/redis/redis-session-store.d.ts +16 -0
- package/dist/lib/adapters/redis/redis-session-store.d.ts.map +1 -0
- package/dist/lib/adapters/redis/redis-session-store.js +49 -0
- package/dist/lib/adapters/redis/redis-session-store.js.map +1 -0
- package/dist/lib/adapters/redis/shared.d.ts +24 -0
- package/dist/lib/adapters/redis/shared.d.ts.map +1 -0
- package/dist/lib/adapters/redis/shared.js +60 -0
- package/dist/lib/adapters/redis/shared.js.map +1 -0
- package/dist/lib/core/authorization-service.d.ts +21 -0
- package/dist/lib/core/authorization-service.d.ts.map +1 -0
- package/dist/lib/core/authorization-service.js +125 -0
- package/dist/lib/core/authorization-service.js.map +1 -0
- package/dist/lib/core/create-auth-module.d.ts +3 -0
- package/dist/lib/core/create-auth-module.d.ts.map +1 -0
- package/dist/lib/core/create-auth-module.js +177 -0
- package/dist/lib/core/create-auth-module.js.map +1 -0
- package/dist/lib/core/defaults.d.ts +4 -0
- package/dist/lib/core/defaults.d.ts.map +1 -0
- package/dist/lib/core/defaults.js +50 -0
- package/dist/lib/core/defaults.js.map +1 -0
- package/dist/lib/core/logger.d.ts +4 -0
- package/dist/lib/core/logger.d.ts.map +1 -0
- package/dist/lib/core/logger.js +14 -0
- package/dist/lib/core/logger.js.map +1 -0
- package/dist/lib/core/session-service.d.ts +33 -0
- package/dist/lib/core/session-service.d.ts.map +1 -0
- package/dist/lib/core/session-service.js +96 -0
- package/dist/lib/core/session-service.js.map +1 -0
- package/dist/lib/core/token-service.d.ts +22 -0
- package/dist/lib/core/token-service.d.ts.map +1 -0
- package/dist/lib/core/token-service.js +111 -0
- package/dist/lib/core/token-service.js.map +1 -0
- package/dist/lib/errors.d.ts +21 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +36 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/ports.d.ts +32 -0
- package/dist/lib/ports.d.ts.map +1 -0
- package/dist/lib/ports.js +2 -0
- package/dist/lib/ports.js.map +1 -0
- package/dist/lib/types.d.ts +161 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/logging.d.ts +2 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +2 -0
- package/dist/logging.js.map +1 -0
- package/dist/memory.d.ts +3 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +3 -0
- package/dist/memory.js.map +1 -0
- package/dist/postgres.d.ts +5 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/postgres.js +5 -0
- package/dist/postgres.js.map +1 -0
- package/dist/redis.d.ts +5 -0
- package/dist/redis.d.ts.map +1 -0
- package/dist/redis.js +5 -0
- package/dist/redis.js.map +1 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# @joethebigbuddy/auth
|
|
2
|
+
|
|
3
|
+
TypeScript authentication and authorization module for Node.js applications.
|
|
4
|
+
|
|
5
|
+
This repo contains a thin auth core plus optional adapters for common application integration paths. The current implementation is Express-first, but the core stays framework-neutral.
|
|
6
|
+
|
|
7
|
+
## What It Provides
|
|
8
|
+
|
|
9
|
+
- login and refresh flows
|
|
10
|
+
- JWT access and refresh token issuance and verification
|
|
11
|
+
- session lifecycle management
|
|
12
|
+
- role and permission authorization
|
|
13
|
+
- explicit typed auth errors
|
|
14
|
+
- Express adapter for request authentication and authorization
|
|
15
|
+
- logging adapter for `@joethebigbuddy/logging`
|
|
16
|
+
- memory, Postgres, and Redis-backed auth storage adapters
|
|
17
|
+
|
|
18
|
+
## Package Exports
|
|
19
|
+
|
|
20
|
+
- `@joethebigbuddy/auth`
|
|
21
|
+
- `@joethebigbuddy/auth/express`
|
|
22
|
+
- `@joethebigbuddy/auth/logging`
|
|
23
|
+
- `@joethebigbuddy/auth/memory`
|
|
24
|
+
- `@joethebigbuddy/auth/postgres`
|
|
25
|
+
- `@joethebigbuddy/auth/redis`
|
|
26
|
+
|
|
27
|
+
## Design Shape
|
|
28
|
+
|
|
29
|
+
The module is built around a few core concepts:
|
|
30
|
+
|
|
31
|
+
- `IdentityProvider`
|
|
32
|
+
verifies credentials and loads subjects
|
|
33
|
+
- `SessionStore`
|
|
34
|
+
persists session records
|
|
35
|
+
- `RefreshTokenStore`
|
|
36
|
+
persists refresh token records
|
|
37
|
+
- `createAuthModule(...)`
|
|
38
|
+
assembles the auth core from config and injected ports
|
|
39
|
+
|
|
40
|
+
This keeps application-specific user persistence outside the package while letting apps choose their own storage backend.
|
|
41
|
+
|
|
42
|
+
## Storage Modes
|
|
43
|
+
|
|
44
|
+
Available today:
|
|
45
|
+
|
|
46
|
+
- memory
|
|
47
|
+
- Postgres
|
|
48
|
+
- Redis
|
|
49
|
+
|
|
50
|
+
Memory mode is the simplest path for tests and local smoke runs.
|
|
51
|
+
|
|
52
|
+
Postgres and Redis adapters are available as concrete stores. Whether you want a combined Postgres-plus-Redis production topology is still an application-level choice rather than a required package mode.
|
|
53
|
+
|
|
54
|
+
## Example
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { createAuthModule, createDefaultAuthConfig } from '@joethebigbuddy/auth';
|
|
58
|
+
import { createExpressAuthAdapter } from '@joethebigbuddy/auth/express';
|
|
59
|
+
import { MemoryRefreshTokenStore, MemorySessionStore } from '@joethebigbuddy/auth/memory';
|
|
60
|
+
|
|
61
|
+
const auth = createAuthModule(
|
|
62
|
+
createDefaultAuthConfig({
|
|
63
|
+
issuer: '@joethebigbuddy/auth',
|
|
64
|
+
audience: 'my-app',
|
|
65
|
+
signing: {
|
|
66
|
+
algorithm: 'HS256',
|
|
67
|
+
secret: process.env.AUTH_SECRET!,
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
{
|
|
71
|
+
identityProvider,
|
|
72
|
+
sessionStore: new MemorySessionStore(),
|
|
73
|
+
refreshTokenStore: new MemoryRefreshTokenStore(),
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const expressAuth = createExpressAuthAdapter(auth, {
|
|
78
|
+
tokenSources: ['authorization-header', 'cookie'],
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Local Verification
|
|
83
|
+
|
|
84
|
+
Main package checks:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm run typecheck
|
|
88
|
+
npm test
|
|
89
|
+
npm run test:coverage
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
For real application-flow verification, use the external sandbox app:
|
|
93
|
+
|
|
94
|
+
- auth module repo: `/Users/jojo/ws/ts/auth`
|
|
95
|
+
- sandbox app repo: `/Users/jojo/ws/ts/auth-sandbox-app`
|
|
96
|
+
|
|
97
|
+
The sandbox app README documents how to run memory, Postgres, and Redis-backed smoke checks against this package.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,cAAc,gDAAgD,CAAC"}
|
package/dist/express.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,cAAc,gDAAgD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './lib/errors.js';
|
|
2
|
+
export * from './lib/ports.js';
|
|
3
|
+
export * from './lib/types.js';
|
|
4
|
+
export * from './lib/core/defaults.js';
|
|
5
|
+
export * from './lib/core/authorization-service.js';
|
|
6
|
+
export * from './lib/core/session-service.js';
|
|
7
|
+
export * from './lib/core/token-service.js';
|
|
8
|
+
export * from './lib/core/create-auth-module.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './lib/errors.js';
|
|
2
|
+
export * from './lib/ports.js';
|
|
3
|
+
export * from './lib/types.js';
|
|
4
|
+
export * from './lib/core/defaults.js';
|
|
5
|
+
export * from './lib/core/authorization-service.js';
|
|
6
|
+
export * from './lib/core/session-service.js';
|
|
7
|
+
export * from './lib/core/token-service.js';
|
|
8
|
+
export * from './lib/core/create-auth-module.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { CookieOptions, NextFunction, Request, Response } from 'express';
|
|
2
|
+
import type { LoggerPort } from '../../ports.js';
|
|
3
|
+
import type { AuthModule, AuthPrincipal, AuthorizationRequirement, SessionRecord } from '../../types.js';
|
|
4
|
+
export interface ExpressAuthContext {
|
|
5
|
+
principal: AuthPrincipal;
|
|
6
|
+
session: SessionRecord | null;
|
|
7
|
+
accessToken: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AuthenticatedRequest extends Request {
|
|
10
|
+
auth?: ExpressAuthContext;
|
|
11
|
+
}
|
|
12
|
+
export interface ExpressAuthAdapterOptions {
|
|
13
|
+
tokenSources?: Array<'authorization-header' | 'cookie'>;
|
|
14
|
+
getRequestId?: (req: Request) => string | undefined;
|
|
15
|
+
logger?: LoggerPort;
|
|
16
|
+
cookie?: {
|
|
17
|
+
accessTokenName: string;
|
|
18
|
+
refreshTokenName: string;
|
|
19
|
+
secure?: boolean;
|
|
20
|
+
httpOnly?: boolean;
|
|
21
|
+
sameSite?: CookieOptions['sameSite'];
|
|
22
|
+
path?: string;
|
|
23
|
+
domain?: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export declare class ExpressAuthAdapter {
|
|
27
|
+
private readonly auth;
|
|
28
|
+
private readonly tokenSources;
|
|
29
|
+
private readonly getRequestId?;
|
|
30
|
+
private readonly logger?;
|
|
31
|
+
private readonly cookie?;
|
|
32
|
+
constructor(auth: AuthModule, options?: ExpressAuthAdapterOptions);
|
|
33
|
+
authenticate: (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
34
|
+
optionalAuthenticate: (req: AuthenticatedRequest, _res: Response, next: NextFunction) => Promise<void>;
|
|
35
|
+
requirePermissions: (permissions: string[], mode?: "all" | "any") => (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
36
|
+
requireRoles: (roles: string[]) => (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
37
|
+
requireAuthorization: (requirement: AuthorizationRequirement) => (req: AuthenticatedRequest, res: Response, next: NextFunction) => Promise<void>;
|
|
38
|
+
writeAuthCookies(res: Response, tokens: {
|
|
39
|
+
accessToken: string;
|
|
40
|
+
refreshToken: string;
|
|
41
|
+
}): void;
|
|
42
|
+
clearAuthCookies(res: Response): void;
|
|
43
|
+
extractAccessToken(req: Request): string | null;
|
|
44
|
+
extractRefreshToken(req: Request): string | null;
|
|
45
|
+
private toCookieOptions;
|
|
46
|
+
}
|
|
47
|
+
export declare function createExpressAuthAdapter(auth: AuthModule, options?: ExpressAuthAdapterOptions): ExpressAuthAdapter;
|
|
48
|
+
//# sourceMappingURL=express-auth-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-auth-adapter.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/express/express-auth-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,wBAAwB,EACxB,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,IAAI,CAAC,EAAE,kBAAkB,CAAC;CAC3B;AAED,MAAM,WAAW,yBAAyB;IACxC,YAAY,CAAC,EAAE,KAAK,CAAC,sBAAsB,GAAG,QAAQ,CAAC,CAAC;IACxD,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;IACpD,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE;QACP,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAuCD,qBAAa,kBAAkB;IAO3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IANvB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2C;IACxE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAuC;IACrE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAsC;gBAG3C,IAAI,EAAE,UAAU,EACjC,OAAO,GAAE,yBAA8B;IAQzC,YAAY,GAAU,KAAK,oBAAoB,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CAoBhG;IAEF,oBAAoB,GAAU,KAAK,oBAAoB,EAAE,MAAM,QAAQ,EAAE,MAAM,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CAezG;IAEF,kBAAkB,GAChB,aAAa,MAAM,EAAE,EACrB,OAAM,KAAK,GAAG,KAAa,WAYR,oBAAoB,OAAO,QAAQ,QAAQ,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CAL1F;IAEF,YAAY,GAAI,OAAO,MAAM,EAAE,WAGV,oBAAoB,OAAO,QAAQ,QAAQ,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CAHnB;IAEzE,oBAAoB,GAAI,aAAa,wBAAwB,MAC7C,KAAK,oBAAoB,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,OAAO,CAAC,IAAI,CAAC,CAgB1F;IAEF,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAS5F,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;IAUrC,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;IAqB/C,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;IAShD,OAAO,CAAC,eAAe;CASxB;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,yBAA8B,GAAG,kBAAkB,CAEtH"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { AuthError, AuthenticationError, AuthorizationError } from '../../errors.js';
|
|
2
|
+
function parseCookieHeader(header) {
|
|
3
|
+
if (!header) {
|
|
4
|
+
return {};
|
|
5
|
+
}
|
|
6
|
+
return header.split(';').reduce((cookies, part) => {
|
|
7
|
+
const [name, ...rest] = part.trim().split('=');
|
|
8
|
+
if (!name) {
|
|
9
|
+
return cookies;
|
|
10
|
+
}
|
|
11
|
+
cookies[name] = decodeURIComponent(rest.join('='));
|
|
12
|
+
return cookies;
|
|
13
|
+
}, {});
|
|
14
|
+
}
|
|
15
|
+
function sendError(res, error) {
|
|
16
|
+
if (error instanceof AuthError) {
|
|
17
|
+
res.status(error.statusCode).json({
|
|
18
|
+
ok: false,
|
|
19
|
+
error: {
|
|
20
|
+
code: error.code,
|
|
21
|
+
message: error.message,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
res.status(500).json({
|
|
27
|
+
ok: false,
|
|
28
|
+
error: {
|
|
29
|
+
code: 'INTERNAL_ERROR',
|
|
30
|
+
message: 'Unexpected authentication error',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export class ExpressAuthAdapter {
|
|
35
|
+
auth;
|
|
36
|
+
tokenSources;
|
|
37
|
+
getRequestId;
|
|
38
|
+
logger;
|
|
39
|
+
cookie;
|
|
40
|
+
constructor(auth, options = {}) {
|
|
41
|
+
this.auth = auth;
|
|
42
|
+
this.tokenSources = options.tokenSources ?? ['authorization-header'];
|
|
43
|
+
this.getRequestId = options.getRequestId;
|
|
44
|
+
this.logger = options.logger;
|
|
45
|
+
this.cookie = options.cookie;
|
|
46
|
+
}
|
|
47
|
+
authenticate = async (req, res, next) => {
|
|
48
|
+
try {
|
|
49
|
+
const accessToken = this.extractAccessToken(req);
|
|
50
|
+
if (!accessToken) {
|
|
51
|
+
throw new AuthenticationError('Missing access token', 'MISSING_ACCESS_TOKEN');
|
|
52
|
+
}
|
|
53
|
+
const principal = await this.auth.authenticateAccessToken(accessToken);
|
|
54
|
+
const session = await this.auth.getSession(principal.sessionId);
|
|
55
|
+
req.auth = { principal, session, accessToken };
|
|
56
|
+
next();
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
this.logger?.warn('Express authenticate failed', {
|
|
60
|
+
requestId: this.getRequestId?.(req),
|
|
61
|
+
path: req.path,
|
|
62
|
+
method: req.method,
|
|
63
|
+
err: error,
|
|
64
|
+
});
|
|
65
|
+
sendError(res, error);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
optionalAuthenticate = async (req, _res, next) => {
|
|
69
|
+
try {
|
|
70
|
+
const accessToken = this.extractAccessToken(req);
|
|
71
|
+
if (!accessToken) {
|
|
72
|
+
next();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const principal = await this.auth.authenticateAccessToken(accessToken);
|
|
76
|
+
const session = await this.auth.getSession(principal.sessionId);
|
|
77
|
+
req.auth = { principal, session, accessToken };
|
|
78
|
+
next();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
next();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
requirePermissions = (permissions, mode = 'all') => {
|
|
85
|
+
const requirement = mode === 'all'
|
|
86
|
+
? { allOf: permissions }
|
|
87
|
+
: { anyOf: permissions };
|
|
88
|
+
return this.requireAuthorization(requirement);
|
|
89
|
+
};
|
|
90
|
+
requireRoles = (roles) => this.requireAuthorization({ roles });
|
|
91
|
+
requireAuthorization = (requirement) => {
|
|
92
|
+
return async (req, res, next) => {
|
|
93
|
+
try {
|
|
94
|
+
if (!req.auth) {
|
|
95
|
+
throw new AuthenticationError('Authentication required', 'AUTHENTICATION_REQUIRED');
|
|
96
|
+
}
|
|
97
|
+
const decision = await this.auth.authorize(req.auth.principal, requirement);
|
|
98
|
+
if (!decision.allowed) {
|
|
99
|
+
throw new AuthorizationError('Forbidden', 'FORBIDDEN');
|
|
100
|
+
}
|
|
101
|
+
next();
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
sendError(res, error);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
writeAuthCookies(res, tokens) {
|
|
109
|
+
if (!this.cookie) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
res.cookie(this.cookie.accessTokenName, tokens.accessToken, this.toCookieOptions());
|
|
113
|
+
res.cookie(this.cookie.refreshTokenName, tokens.refreshToken, this.toCookieOptions());
|
|
114
|
+
}
|
|
115
|
+
clearAuthCookies(res) {
|
|
116
|
+
if (!this.cookie) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const cookieOptions = this.toCookieOptions();
|
|
120
|
+
res.clearCookie(this.cookie.accessTokenName, cookieOptions);
|
|
121
|
+
res.clearCookie(this.cookie.refreshTokenName, cookieOptions);
|
|
122
|
+
}
|
|
123
|
+
extractAccessToken(req) {
|
|
124
|
+
for (const source of this.tokenSources) {
|
|
125
|
+
if (source === 'authorization-header') {
|
|
126
|
+
const header = req.headers.authorization;
|
|
127
|
+
if (header?.startsWith('Bearer ')) {
|
|
128
|
+
return header.slice('Bearer '.length).trim();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (source === 'cookie' && this.cookie) {
|
|
132
|
+
const cookies = parseCookieHeader(req.headers.cookie);
|
|
133
|
+
const token = cookies[this.cookie.accessTokenName];
|
|
134
|
+
if (token) {
|
|
135
|
+
return token;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
extractRefreshToken(req) {
|
|
142
|
+
if (!this.cookie) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const cookies = parseCookieHeader(req.headers.cookie);
|
|
146
|
+
return cookies[this.cookie.refreshTokenName] ?? null;
|
|
147
|
+
}
|
|
148
|
+
toCookieOptions() {
|
|
149
|
+
return {
|
|
150
|
+
httpOnly: this.cookie?.httpOnly ?? true,
|
|
151
|
+
secure: this.cookie?.secure ?? true,
|
|
152
|
+
sameSite: this.cookie?.sameSite ?? 'lax',
|
|
153
|
+
path: this.cookie?.path ?? '/',
|
|
154
|
+
domain: this.cookie?.domain,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function createExpressAuthAdapter(auth, options = {}) {
|
|
159
|
+
return new ExpressAuthAdapter(auth, options);
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=express-auth-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-auth-adapter.js","sourceRoot":"","sources":["../../../../src/lib/adapters/express/express-auth-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-logging-adapter.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/logging/create-logging-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAkB/D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function createLoggingAdapter(logger) {
|
|
2
|
+
return {
|
|
3
|
+
debug(message, fields) {
|
|
4
|
+
logger.debug(message, fields);
|
|
5
|
+
},
|
|
6
|
+
info(message, fields) {
|
|
7
|
+
logger.info(message, fields);
|
|
8
|
+
},
|
|
9
|
+
warn(message, fields) {
|
|
10
|
+
logger.warn(message, fields);
|
|
11
|
+
},
|
|
12
|
+
error(message, fields) {
|
|
13
|
+
logger.error(message, fields);
|
|
14
|
+
},
|
|
15
|
+
child(fields) {
|
|
16
|
+
return createLoggingAdapter(logger.child(fields));
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=create-logging-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-logging-adapter.js","sourceRoot":"","sources":["../../../../src/lib/adapters/logging/create-logging-adapter.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO;QACL,KAAK,CAAC,OAAO,EAAE,MAAM;YACnB,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,MAAM;YAClB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,MAAM;YAClB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,OAAO,EAAE,MAAM;YACnB,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,KAAK,CAAC,MAAM;YACV,OAAO,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QACpD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RefreshTokenStore } from '../../ports.js';
|
|
2
|
+
import type { RefreshTokenRecord } from '../../types.js';
|
|
3
|
+
export declare class MemoryRefreshTokenStore implements RefreshTokenStore {
|
|
4
|
+
private readonly records;
|
|
5
|
+
save(record: RefreshTokenRecord): Promise<void>;
|
|
6
|
+
get(tokenId: string): Promise<RefreshTokenRecord | null>;
|
|
7
|
+
revoke(tokenId: string): Promise<void>;
|
|
8
|
+
revokeBySession(sessionId: string): Promise<number>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=memory-refresh-token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-refresh-token-store.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/memory/memory-refresh-token-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IAE3D,IAAI,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAKxD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAa1D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class MemoryRefreshTokenStore {
|
|
2
|
+
records = new Map();
|
|
3
|
+
async save(record) {
|
|
4
|
+
this.records.set(record.tokenId, { ...record });
|
|
5
|
+
}
|
|
6
|
+
async get(tokenId) {
|
|
7
|
+
const record = this.records.get(tokenId);
|
|
8
|
+
return record ? { ...record } : null;
|
|
9
|
+
}
|
|
10
|
+
async revoke(tokenId) {
|
|
11
|
+
const record = this.records.get(tokenId);
|
|
12
|
+
if (!record) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
this.records.set(tokenId, {
|
|
16
|
+
...record,
|
|
17
|
+
revokedAt: new Date(),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async revokeBySession(sessionId) {
|
|
21
|
+
let count = 0;
|
|
22
|
+
for (const [tokenId, record] of this.records.entries()) {
|
|
23
|
+
if (record.sessionId === sessionId && !record.revokedAt) {
|
|
24
|
+
this.records.set(tokenId, {
|
|
25
|
+
...record,
|
|
26
|
+
revokedAt: new Date(),
|
|
27
|
+
});
|
|
28
|
+
count += 1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return count;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=memory-refresh-token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-refresh-token-store.js","sourceRoot":"","sources":["../../../../src/lib/adapters/memory/memory-refresh-token-store.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,uBAAuB;IACjB,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;IAEjE,KAAK,CAAC,IAAI,CAAC,MAA0B;QACnC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,OAAe;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE;YACxB,GAAG,MAAM;YACT,SAAS,EAAE,IAAI,IAAI,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,SAAiB;QACrC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YACvD,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;gBACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE;oBACxB,GAAG,MAAM;oBACT,SAAS,EAAE,IAAI,IAAI,EAAE;iBACtB,CAAC,CAAC;gBACH,KAAK,IAAI,CAAC,CAAC;YACb,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SessionStore } from '../../ports.js';
|
|
2
|
+
import type { SessionRecord } from '../../types.js';
|
|
3
|
+
export declare class MemorySessionStore implements SessionStore {
|
|
4
|
+
private readonly sessions;
|
|
5
|
+
create(session: SessionRecord): Promise<void>;
|
|
6
|
+
get(sessionId: string): Promise<SessionRecord | null>;
|
|
7
|
+
update(session: SessionRecord): Promise<void>;
|
|
8
|
+
delete(sessionId: string): Promise<void>;
|
|
9
|
+
deleteBySubject(subjectId: string): Promise<number>;
|
|
10
|
+
listBySubject(subjectId: string): Promise<SessionRecord[]>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=memory-session-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-session-store.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/memory/memory-session-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAEvD,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKrD,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAWnD,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CAKjE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class MemorySessionStore {
|
|
2
|
+
sessions = new Map();
|
|
3
|
+
async create(session) {
|
|
4
|
+
this.sessions.set(session.id, { ...session });
|
|
5
|
+
}
|
|
6
|
+
async get(sessionId) {
|
|
7
|
+
const session = this.sessions.get(sessionId);
|
|
8
|
+
return session ? { ...session } : null;
|
|
9
|
+
}
|
|
10
|
+
async update(session) {
|
|
11
|
+
this.sessions.set(session.id, { ...session });
|
|
12
|
+
}
|
|
13
|
+
async delete(sessionId) {
|
|
14
|
+
this.sessions.delete(sessionId);
|
|
15
|
+
}
|
|
16
|
+
async deleteBySubject(subjectId) {
|
|
17
|
+
let deleted = 0;
|
|
18
|
+
for (const [sessionId, session] of this.sessions.entries()) {
|
|
19
|
+
if (session.subjectId === subjectId) {
|
|
20
|
+
this.sessions.delete(sessionId);
|
|
21
|
+
deleted += 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return deleted;
|
|
25
|
+
}
|
|
26
|
+
async listBySubject(subjectId) {
|
|
27
|
+
return Array.from(this.sessions.values())
|
|
28
|
+
.filter((session) => session.subjectId === subjectId)
|
|
29
|
+
.map((session) => ({ ...session }));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=memory-session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-session-store.js","sourceRoot":"","sources":["../../../../src/lib/adapters/memory/memory-session-store.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,kBAAkB;IACZ,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAE7D,KAAK,CAAC,MAAM,CAAC,OAAsB;QACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,SAAiB;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAsB;QACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAAiB;QAC5B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,SAAiB;QACrC,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3D,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;gBAChC,OAAO,IAAI,CAAC,CAAC;YACf,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,SAAiB;QACnC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;aACtC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;aACpD,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Pool, type PoolConfig } from 'pg';
|
|
2
|
+
import { PostgresRefreshTokenStore } from './postgres-refresh-token-store.js';
|
|
3
|
+
import { PostgresSessionStore } from './postgres-session-store.js';
|
|
4
|
+
import { type PostgresAuthTablesOptions } from './shared.js';
|
|
5
|
+
export interface CreatePostgresAuthStorageOptions extends PostgresAuthTablesOptions {
|
|
6
|
+
connectionString: string;
|
|
7
|
+
pool?: PoolConfig;
|
|
8
|
+
}
|
|
9
|
+
export declare function createPostgresAuthStorage(options: CreatePostgresAuthStorageOptions): {
|
|
10
|
+
pool: Pool;
|
|
11
|
+
sessionStore: PostgresSessionStore;
|
|
12
|
+
refreshTokenStore: PostgresRefreshTokenStore;
|
|
13
|
+
ensureSchema: () => Promise<void>;
|
|
14
|
+
close: () => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=create-postgres-auth-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-postgres-auth-storage.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/postgres/create-postgres-auth-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAA4B,KAAK,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAEvF,MAAM,WAAW,gCAAiC,SAAQ,yBAAyB;IACjF,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gCAAgC;;;;;;EAalF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { PostgresRefreshTokenStore } from './postgres-refresh-token-store.js';
|
|
3
|
+
import { PostgresSessionStore } from './postgres-session-store.js';
|
|
4
|
+
import { ensurePostgresAuthTables } from './shared.js';
|
|
5
|
+
export function createPostgresAuthStorage(options) {
|
|
6
|
+
const pool = new Pool({
|
|
7
|
+
connectionString: options.connectionString,
|
|
8
|
+
...options.pool,
|
|
9
|
+
});
|
|
10
|
+
return {
|
|
11
|
+
pool,
|
|
12
|
+
sessionStore: new PostgresSessionStore(pool, options),
|
|
13
|
+
refreshTokenStore: new PostgresRefreshTokenStore(pool, options),
|
|
14
|
+
ensureSchema: () => ensurePostgresAuthTables(pool, options),
|
|
15
|
+
close: () => pool.end(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=create-postgres-auth-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-postgres-auth-storage.js","sourceRoot":"","sources":["../../../../src/lib/adapters/postgres/create-postgres-auth-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAAkC,MAAM,aAAa,CAAC;AAOvF,MAAM,UAAU,yBAAyB,CAAC,OAAyC;IACjF,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;QACpB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,GAAG,OAAO,CAAC,IAAI;KAChB,CAAC,CAAC;IAEH,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,IAAI,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC;QACrD,iBAAiB,EAAE,IAAI,yBAAyB,CAAC,IAAI,EAAE,OAAO,CAAC;QAC/D,YAAY,EAAE,GAAG,EAAE,CAAC,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC;QAC3D,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;KACxB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RefreshTokenStore } from '../../ports.js';
|
|
2
|
+
import type { RefreshTokenRecord } from '../../types.js';
|
|
3
|
+
import { type PostgresAuthTablesOptions, type PostgresQueryable } from './shared.js';
|
|
4
|
+
export declare class PostgresRefreshTokenStore implements RefreshTokenStore {
|
|
5
|
+
private readonly client;
|
|
6
|
+
private readonly tableName;
|
|
7
|
+
constructor(client: PostgresQueryable, options?: PostgresAuthTablesOptions);
|
|
8
|
+
save(record: RefreshTokenRecord): Promise<void>;
|
|
9
|
+
get(tokenId: string): Promise<RefreshTokenRecord | null>;
|
|
10
|
+
revoke(tokenId: string): Promise<void>;
|
|
11
|
+
revokeBySession(sessionId: string): Promise<number>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=postgres-refresh-token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-refresh-token-store.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/postgres/postgres-refresh-token-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EAEvB,MAAM,aAAa,CAAC;AAErB,qBAAa,yBAA0B,YAAW,iBAAiB;IAI/D,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGhB,MAAM,EAAE,iBAAiB,EAC1C,OAAO,GAAE,yBAA8B;IAKnC,IAAI,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC/C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IASxD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWtC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAY1D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { mapPostgresRefreshTokenRow, resolvePostgresAuthTables, } from './shared.js';
|
|
2
|
+
export class PostgresRefreshTokenStore {
|
|
3
|
+
client;
|
|
4
|
+
tableName;
|
|
5
|
+
constructor(client, options = {}) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
this.tableName = resolvePostgresAuthTables(options).refreshTokensTableName;
|
|
8
|
+
}
|
|
9
|
+
async save(record) {
|
|
10
|
+
await this.client.query(`
|
|
11
|
+
insert into ${this.tableName} (
|
|
12
|
+
token_id,
|
|
13
|
+
session_id,
|
|
14
|
+
subject_id,
|
|
15
|
+
token,
|
|
16
|
+
issued_at,
|
|
17
|
+
expires_at,
|
|
18
|
+
consumed_at,
|
|
19
|
+
revoked_at,
|
|
20
|
+
replaced_by_token_id
|
|
21
|
+
) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
22
|
+
on conflict (token_id) do update set
|
|
23
|
+
session_id = excluded.session_id,
|
|
24
|
+
subject_id = excluded.subject_id,
|
|
25
|
+
token = excluded.token,
|
|
26
|
+
issued_at = excluded.issued_at,
|
|
27
|
+
expires_at = excluded.expires_at,
|
|
28
|
+
consumed_at = excluded.consumed_at,
|
|
29
|
+
revoked_at = excluded.revoked_at,
|
|
30
|
+
replaced_by_token_id = excluded.replaced_by_token_id
|
|
31
|
+
`, [
|
|
32
|
+
record.tokenId,
|
|
33
|
+
record.sessionId,
|
|
34
|
+
record.subjectId,
|
|
35
|
+
record.token,
|
|
36
|
+
record.issuedAt,
|
|
37
|
+
record.expiresAt,
|
|
38
|
+
record.consumedAt ?? null,
|
|
39
|
+
record.revokedAt ?? null,
|
|
40
|
+
record.replacedByTokenId ?? null,
|
|
41
|
+
]);
|
|
42
|
+
}
|
|
43
|
+
async get(tokenId) {
|
|
44
|
+
const result = await this.client.query(`select * from ${this.tableName} where token_id = $1 limit 1`, [tokenId]);
|
|
45
|
+
return result.rows[0] ? mapPostgresRefreshTokenRow(result.rows[0]) : null;
|
|
46
|
+
}
|
|
47
|
+
async revoke(tokenId) {
|
|
48
|
+
await this.client.query(`
|
|
49
|
+
update ${this.tableName}
|
|
50
|
+
set revoked_at = coalesce(revoked_at, $2)
|
|
51
|
+
where token_id = $1
|
|
52
|
+
`, [tokenId, new Date()]);
|
|
53
|
+
}
|
|
54
|
+
async revokeBySession(sessionId) {
|
|
55
|
+
const result = await this.client.query(`
|
|
56
|
+
update ${this.tableName}
|
|
57
|
+
set revoked_at = coalesce(revoked_at, $2)
|
|
58
|
+
where session_id = $1 and revoked_at is null
|
|
59
|
+
`, [sessionId, new Date()]);
|
|
60
|
+
return result.rowCount ?? 0;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=postgres-refresh-token-store.js.map
|