@fluojs/passport 1.0.0-beta.3 → 1.0.0-beta.5
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.ko.md +34 -1
- package/README.md +34 -1
- package/dist/cookie/cookie-auth.d.ts +6 -1
- package/dist/cookie/cookie-auth.d.ts.map +1 -1
- package/dist/cookie/cookie-auth.js +12 -9
- package/dist/cookie/cookie-manager.d.ts +21 -0
- package/dist/cookie/cookie-manager.d.ts.map +1 -1
- package/dist/cookie/cookie-manager.js +27 -0
- package/dist/decorators.d.ts +20 -0
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +28 -0
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +9 -0
- package/dist/internal-tokens.d.ts +6 -0
- package/dist/internal-tokens.d.ts.map +1 -1
- package/dist/internal-tokens.js +7 -0
- package/dist/metadata.d.ts +21 -0
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +27 -1
- package/dist/scope.d.ts +19 -0
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js +25 -1
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
package/README.ko.md
CHANGED
|
@@ -114,9 +114,27 @@ export class AuthModule {}
|
|
|
114
114
|
|
|
115
115
|
`CookieAuthStrategy`는 `@fluojs/jwt`가 정규화한 JWT principal 계약을 보존하며, `subject`, `claims`, `issuer`, `audience`, `roles`, `scopes`를 그대로 전달합니다.
|
|
116
116
|
|
|
117
|
+
보호된 라우트는 계속 `@UseAuth(...)`를 사용해야 합니다. `requireAccessToken: false`를 설정해도 쿠키가 없을 때는 익명 principal이 아니라 명시적인 미인증 결과를 반환하므로, 보호된 라우트는 요청을 계속 거부합니다.
|
|
118
|
+
|
|
119
|
+
로그인 사용자와 게스트 호출자를 모두 허용하려는 라우트에서만 `@UseOptionalAuth(...)`를 사용하세요.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { Controller, Get, type RequestContext } from '@fluojs/http';
|
|
123
|
+
import { UseOptionalAuth } from '@fluojs/passport';
|
|
124
|
+
|
|
125
|
+
@Controller('/session')
|
|
126
|
+
export class SessionController {
|
|
127
|
+
@Get('/')
|
|
128
|
+
@UseOptionalAuth('cookie')
|
|
129
|
+
getSession(_input: never, ctx: RequestContext) {
|
|
130
|
+
return { subject: ctx.principal?.subject ?? null };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
117
135
|
### 리프레시 토큰 수명 주기
|
|
118
136
|
|
|
119
|
-
|
|
137
|
+
패키지는 안전한 토큰 rotation과 revocation을 위해 built-in `RefreshTokenStrategy`, `RefreshTokenModule`, `RefreshTokenService` contract를 제공합니다.
|
|
120
138
|
|
|
121
139
|
```typescript
|
|
122
140
|
import { Module } from '@fluojs/core';
|
|
@@ -153,10 +171,19 @@ export class AuthController {
|
|
|
153
171
|
|
|
154
172
|
`RefreshTokenModule.forRoot(...)`를 `PassportModule.forRoot(...)`와 함께 import 하여 refresh-token 전략과 공유 `REFRESH_TOKEN_SERVICE` alias를 같은 모듈 wiring에서 사용하세요.
|
|
155
173
|
|
|
174
|
+
`RefreshTokenStrategy`는 `body.refreshToken`, `Authorization: Bearer ...`, `x-refresh-token`에서 token을 읽습니다. Malformed non-string token은 인증 실패로 처리됩니다. `JwtRefreshTokenAdapter`는 `secret`과 backing store가 필요하며, `store: 'memory'`는 development 및 single-instance deployment용입니다.
|
|
175
|
+
|
|
176
|
+
### Account linking과 status
|
|
177
|
+
|
|
178
|
+
Identity-link 결정을 모델링하려면 `createConservativeAccountLinkPolicy(...)`와 `resolveAccountLinking(...)`을 사용합니다. 기본 conservative policy는 명시적인 existing link 또는 user-confirmed match만 연결하고, 그 외에는 create/skip/reject/conflict를 결정적으로 처리합니다.
|
|
179
|
+
|
|
180
|
+
`createPassportPlatformStatusSnapshot(...)`와 `createPassportPlatformDiagnosticIssues(...)`는 등록된 strategy, default strategy 설정, preset, refresh-token store readiness에 대한 readiness/health diagnostic을 노출합니다.
|
|
181
|
+
|
|
156
182
|
## 공개 API 개요
|
|
157
183
|
|
|
158
184
|
### 데코레이터
|
|
159
185
|
- `@UseAuth(strategyName)`: `AuthGuard`를 부착하고 사용할 전략을 설정합니다.
|
|
186
|
+
- `@UseOptionalAuth(strategyName)`: `AuthGuard`를 부착하지만 전략이 자격 증명 누락을 보고하면 스코프가 없는 라우트는 계속 진행할 수 있게 합니다.
|
|
160
187
|
- `@RequireScopes(...scopes)`: 특정 권한(스코프) 요구 사항을 강제합니다.
|
|
161
188
|
|
|
162
189
|
### 주요 클래스
|
|
@@ -166,11 +193,17 @@ export class AuthController {
|
|
|
166
193
|
- `CookieManager`: HttpOnly 인증 쿠키 관리를 위한 유틸리티입니다.
|
|
167
194
|
- `RefreshTokenModule`: 내장 refresh-token 프리셋의 모듈 진입점입니다.
|
|
168
195
|
- `JwtRefreshTokenAdapter`: `@fluojs/jwt`의 리프레시 로직을 패스포트 인터페이스로 연결합니다.
|
|
196
|
+
- `createPassportJsStrategyBridge(...)`: Passport.js strategy를 fluo `AuthStrategy`로 변환합니다.
|
|
197
|
+
- Cookie helper: `createCookieAuthPreset`, `createCookieAuthStrategyRegistration`, `createCookieManager`, `normalizeCookieAuthOptions`.
|
|
198
|
+
- Refresh helper: `createRefreshTokenStrategyRegistration`.
|
|
199
|
+
- Status/diagnostics helper: `createPassportPlatformStatusSnapshot`, `createPassportPlatformDiagnosticIssues`.
|
|
169
200
|
|
|
170
201
|
### 인터페이스
|
|
171
202
|
- `AuthStrategy`: 커스텀 인증 로직 구현을 위한 계약입니다.
|
|
172
203
|
- `AccountLinkPolicy`: 계정 연결 결정 로직을 위한 확장 지점입니다.
|
|
173
204
|
|
|
205
|
+
`UseOptionalAuth`는 scope가 필요 없는 route에서만 credential 누락을 우회합니다. Scoped route에는 여전히 principal이 필요합니다. Passport.js bridge의 `redirect()`는 response를 commit하고 protected handler를 건너뛰며, `pass()`와 Passport action 없이 완료된 strategy는 인증 실패입니다.
|
|
206
|
+
|
|
174
207
|
## 관련 패키지
|
|
175
208
|
|
|
176
209
|
- `@fluojs/jwt`: JWT 기반 전략을 위한 하위 토큰 코어 패키지입니다.
|
package/README.md
CHANGED
|
@@ -114,9 +114,27 @@ Import `CookieAuthModule.forRoot(...)` alongside `PassportModule.forRoot(...)` w
|
|
|
114
114
|
|
|
115
115
|
`CookieAuthStrategy` preserves the normalized JWT principal contract from `@fluojs/jwt`, including `subject`, `claims`, `issuer`, `audience`, `roles`, and `scopes`.
|
|
116
116
|
|
|
117
|
+
Protected routes must keep using `@UseAuth(...)`. If you configure `requireAccessToken: false`, a missing cookie resolves to an explicit unauthenticated result instead of an anonymous principal, so protected routes still reject the request.
|
|
118
|
+
|
|
119
|
+
Use `@UseOptionalAuth(...)` only on routes that intentionally support both signed-in and guest callers:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { Controller, Get, type RequestContext } from '@fluojs/http';
|
|
123
|
+
import { UseOptionalAuth } from '@fluojs/passport';
|
|
124
|
+
|
|
125
|
+
@Controller('/session')
|
|
126
|
+
export class SessionController {
|
|
127
|
+
@Get('/')
|
|
128
|
+
@UseOptionalAuth('cookie')
|
|
129
|
+
getSession(_input: never, ctx: RequestContext) {
|
|
130
|
+
return { subject: ctx.principal?.subject ?? null };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
117
135
|
### Refresh Token Lifecycle
|
|
118
136
|
|
|
119
|
-
The package provides a built-in `RefreshTokenStrategy` and `RefreshTokenService`
|
|
137
|
+
The package provides a built-in `RefreshTokenStrategy` plus the `RefreshTokenModule` and `RefreshTokenService` contract for secure token rotation and revocation.
|
|
120
138
|
|
|
121
139
|
```typescript
|
|
122
140
|
import { Module } from '@fluojs/core';
|
|
@@ -153,10 +171,19 @@ export class AuthController {
|
|
|
153
171
|
|
|
154
172
|
Import `RefreshTokenModule.forRoot(...)` alongside `PassportModule.forRoot(...)` so the refresh-token strategy and shared `REFRESH_TOKEN_SERVICE` alias are available in the same module wiring.
|
|
155
173
|
|
|
174
|
+
`RefreshTokenStrategy` reads tokens from `body.refreshToken`, `Authorization: Bearer ...`, or `x-refresh-token`; malformed non-string tokens fail authentication. `JwtRefreshTokenAdapter` requires a `secret` and a backing store; `store: 'memory'` is for development and single-instance deployments only.
|
|
175
|
+
|
|
176
|
+
### Account Linking and Status
|
|
177
|
+
|
|
178
|
+
Use `createConservativeAccountLinkPolicy(...)` and `resolveAccountLinking(...)` to model identity-link decisions. The default conservative policy links explicit existing links or user-confirmed matches, and otherwise creates, skips, rejects, or reports conflicts deterministically.
|
|
179
|
+
|
|
180
|
+
`createPassportPlatformStatusSnapshot(...)` and `createPassportPlatformDiagnosticIssues(...)` expose readiness/health diagnostics for registered strategies, default strategy configuration, presets, and refresh-token store readiness.
|
|
181
|
+
|
|
156
182
|
## Public API Overview
|
|
157
183
|
|
|
158
184
|
### Decorators
|
|
159
185
|
- `@UseAuth(strategyName)`: Attaches `AuthGuard` and sets the active strategy.
|
|
186
|
+
- `@UseOptionalAuth(strategyName)`: Attaches `AuthGuard` but allows routes without scopes to continue when the strategy reports missing credentials.
|
|
160
187
|
- `@RequireScopes(...scopes)`: Enforces specific scope requirements.
|
|
161
188
|
|
|
162
189
|
### Core Classes
|
|
@@ -166,11 +193,17 @@ Import `RefreshTokenModule.forRoot(...)` alongside `PassportModule.forRoot(...)`
|
|
|
166
193
|
- `CookieManager`: Utility for managing HttpOnly auth cookies.
|
|
167
194
|
- `RefreshTokenModule`: Module entry point for the built-in refresh-token preset.
|
|
168
195
|
- `JwtRefreshTokenAdapter`: Bridges `@fluojs/jwt` refresh logic to the passport interface.
|
|
196
|
+
- `createPassportJsStrategyBridge(...)`: Adapts Passport.js strategies to fluo `AuthStrategy`.
|
|
197
|
+
- Cookie helpers: `createCookieAuthPreset`, `createCookieAuthStrategyRegistration`, `createCookieManager`, `normalizeCookieAuthOptions`.
|
|
198
|
+
- Refresh helpers: `createRefreshTokenStrategyRegistration`.
|
|
199
|
+
- Status/diagnostics helpers: `createPassportPlatformStatusSnapshot`, `createPassportPlatformDiagnosticIssues`.
|
|
169
200
|
|
|
170
201
|
### Interfaces
|
|
171
202
|
- `AuthStrategy`: The contract for implementing custom authentication logic.
|
|
172
203
|
- `AccountLinkPolicy`: Extension point for identity-linking decisions.
|
|
173
204
|
|
|
205
|
+
`UseOptionalAuth` only bypasses missing credentials when no scopes are required; scoped routes still need a principal. Passport.js bridge `redirect()` commits the response and skips the protected handler, while `pass()` and strategy completion without a Passport action are authentication failures.
|
|
206
|
+
|
|
174
207
|
## Related Packages
|
|
175
208
|
|
|
176
209
|
- `@fluojs/jwt`: The underlying token core for JWT-based strategies.
|
|
@@ -6,7 +6,7 @@ import type { AuthStrategy, AuthStrategyResult } from '../types.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare const COOKIE_AUTH_OPTIONS: unique symbol;
|
|
8
8
|
/**
|
|
9
|
-
* Configures cookie names and
|
|
9
|
+
* Configures cookie names and missing-cookie behavior for cookie-based authentication.
|
|
10
10
|
*/
|
|
11
11
|
export interface CookieAuthOptions {
|
|
12
12
|
accessTokenCookieName?: string;
|
|
@@ -26,6 +26,11 @@ export declare const DEFAULT_COOKIE_AUTH_OPTIONS: Required<CookieAuthOptions>;
|
|
|
26
26
|
export declare function normalizeCookieAuthOptions(options?: CookieAuthOptions): Required<CookieAuthOptions>;
|
|
27
27
|
/**
|
|
28
28
|
* Authenticates requests by reading and verifying JWTs from HTTP cookies.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* When `requireAccessToken` is `false`, missing cookies now resolve to an explicit
|
|
32
|
+
* unauthenticated result. Protected routes still reject that result unless they opt in
|
|
33
|
+
* with `@UseOptionalAuth(...)`.
|
|
29
34
|
*/
|
|
30
35
|
export declare class CookieAuthStrategy implements AuthStrategy {
|
|
31
36
|
private readonly verifier;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie-auth.d.ts","sourceRoot":"","sources":["../../src/cookie/cookie-auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"cookie-auth.d.ts","sourceRoot":"","sources":["../../src/cookie/cookie-auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,KAAK,EAAsB,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAMxF;;GAEG;AACH,eAAO,MAAM,mBAAmB,eAAkD,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B,EAAE,QAAQ,CAAC,iBAAiB,CAInE,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAMnG;AAED;;;;;;;GAOG;AACH,qBACa,kBAAmB,YAAW,YAAY;IAInD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAH3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;gBAGnC,QAAQ,EAAE,kBAAkB,EAC7C,OAAO,CAAC,EAAE,iBAAiB;IAKvB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAyCvE;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,WAAW,CAAC"}
|
|
@@ -7,13 +7,17 @@ function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side
|
|
|
7
7
|
import { Inject } from '@fluojs/core';
|
|
8
8
|
import { DefaultJwtVerifier } from '@fluojs/jwt';
|
|
9
9
|
import { AuthenticationRequiredError } from '../errors.js';
|
|
10
|
+
const unauthenticatedCookieAuthResult = {
|
|
11
|
+
authenticated: false
|
|
12
|
+
};
|
|
13
|
+
|
|
10
14
|
/**
|
|
11
15
|
* Provides cookie-auth strategy options through dependency injection.
|
|
12
16
|
*/
|
|
13
17
|
export const COOKIE_AUTH_OPTIONS = Symbol.for('fluo.passport.cookie-auth-options');
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
|
-
* Configures cookie names and
|
|
20
|
+
* Configures cookie names and missing-cookie behavior for cookie-based authentication.
|
|
17
21
|
*/
|
|
18
22
|
|
|
19
23
|
/**
|
|
@@ -41,6 +45,11 @@ export function normalizeCookieAuthOptions(options) {
|
|
|
41
45
|
|
|
42
46
|
/**
|
|
43
47
|
* Authenticates requests by reading and verifying JWTs from HTTP cookies.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* When `requireAccessToken` is `false`, missing cookies now resolve to an explicit
|
|
51
|
+
* unauthenticated result. Protected routes still reject that result unless they opt in
|
|
52
|
+
* with `@UseOptionalAuth(...)`.
|
|
44
53
|
*/
|
|
45
54
|
let _CookieAuthStrategy;
|
|
46
55
|
class CookieAuthStrategy {
|
|
@@ -59,20 +68,14 @@ class CookieAuthStrategy {
|
|
|
59
68
|
if (this.options.requireAccessToken) {
|
|
60
69
|
throw new AuthenticationRequiredError('Access token cookie is required.');
|
|
61
70
|
}
|
|
62
|
-
return
|
|
63
|
-
claims: {},
|
|
64
|
-
subject: 'anonymous'
|
|
65
|
-
};
|
|
71
|
+
return unauthenticatedCookieAuthResult;
|
|
66
72
|
}
|
|
67
73
|
const accessToken = cookies[this.options.accessTokenCookieName];
|
|
68
74
|
if (!accessToken) {
|
|
69
75
|
if (this.options.requireAccessToken) {
|
|
70
76
|
throw new AuthenticationRequiredError('Access token cookie is required.');
|
|
71
77
|
}
|
|
72
|
-
return
|
|
73
|
-
claims: {},
|
|
74
|
-
subject: 'anonymous'
|
|
75
|
-
};
|
|
78
|
+
return unauthenticatedCookieAuthResult;
|
|
76
79
|
}
|
|
77
80
|
try {
|
|
78
81
|
const principal = await this.verifier.verifyAccessToken(accessToken);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { FrameworkResponse } from '@fluojs/http';
|
|
2
2
|
import { type CookieAuthOptions } from './cookie-auth.js';
|
|
3
|
+
/**
|
|
4
|
+
* Describes the cookie options contract.
|
|
5
|
+
*/
|
|
3
6
|
export interface CookieOptions {
|
|
4
7
|
httpOnly?: boolean;
|
|
5
8
|
secure?: boolean;
|
|
@@ -8,15 +11,27 @@ export interface CookieOptions {
|
|
|
8
11
|
domain?: string;
|
|
9
12
|
maxAge?: number;
|
|
10
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Describes the set cookie options contract.
|
|
16
|
+
*/
|
|
11
17
|
export interface SetCookieOptions extends CookieOptions {
|
|
12
18
|
accessTokenTtlSeconds?: number;
|
|
13
19
|
refreshTokenTtlSeconds?: number;
|
|
14
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Describes the cookie manager config contract.
|
|
23
|
+
*/
|
|
15
24
|
export interface CookieManagerConfig extends CookieAuthOptions {
|
|
16
25
|
cookieOptions?: CookieOptions;
|
|
17
26
|
}
|
|
18
27
|
type NormalizedCookieOptions = Omit<Required<CookieOptions>, 'domain' | 'maxAge'> & Pick<CookieOptions, 'domain' | 'maxAge'>;
|
|
28
|
+
/**
|
|
29
|
+
* Provides the default cookie options value.
|
|
30
|
+
*/
|
|
19
31
|
export declare const DEFAULT_COOKIE_OPTIONS: NormalizedCookieOptions;
|
|
32
|
+
/**
|
|
33
|
+
* Represents the cookie manager.
|
|
34
|
+
*/
|
|
20
35
|
export declare class CookieManager {
|
|
21
36
|
private readonly options;
|
|
22
37
|
private readonly cookieOptions;
|
|
@@ -29,6 +44,12 @@ export declare class CookieManager {
|
|
|
29
44
|
setAuthCookies(response: FrameworkResponse, accessToken: string, accessTokenTtlSeconds?: number, refreshToken?: string, refreshTokenTtlSeconds?: number): void;
|
|
30
45
|
private appendSetCookie;
|
|
31
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Create cookie manager.
|
|
49
|
+
*
|
|
50
|
+
* @param config The config.
|
|
51
|
+
* @returns The create cookie manager result.
|
|
52
|
+
*/
|
|
32
53
|
export declare function createCookieManager(config?: CookieManagerConfig): CookieManager;
|
|
33
54
|
export {};
|
|
34
55
|
//# sourceMappingURL=cookie-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie-manager.d.ts","sourceRoot":"","sources":["../../src/cookie/cookie-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAA+B,KAAK,iBAAiB,EAA8B,MAAM,kBAAkB,CAAC;AAEnH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,KAAK,uBAAuB,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC,GAC/E,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAE3C,eAAO,MAAM,sBAAsB,EAAE,uBAOpC,CAAC;AAuCF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IACtD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;gBAE5C,MAAM,CAAC,EAAE,mBAAmB;IAYxC,oBAAoB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAa3F,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAa5F,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IASzD,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAS1D,eAAe,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAKlD,cAAc,CACZ,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,MAAM,EACnB,qBAAqB,CAAC,EAAE,MAAM,EAC9B,YAAY,CAAC,EAAE,MAAM,EACrB,sBAAsB,CAAC,EAAE,MAAM,GAC9B,IAAI;IAQP,OAAO,CAAC,eAAe;CAWxB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAE/E"}
|
|
1
|
+
{"version":3,"file":"cookie-manager.d.ts","sourceRoot":"","sources":["../../src/cookie/cookie-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAA+B,KAAK,iBAAiB,EAA8B,MAAM,kBAAkB,CAAC;AAEnH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,KAAK,uBAAuB,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC,GAC/E,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,uBAOpC,CAAC;AAuCF;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IACtD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;gBAE5C,MAAM,CAAC,EAAE,mBAAmB;IAYxC,oBAAoB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAa3F,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAa5F,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IASzD,uBAAuB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAS1D,eAAe,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAKlD,cAAc,CACZ,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,MAAM,EACnB,qBAAqB,CAAC,EAAE,MAAM,EAC9B,YAAY,CAAC,EAAE,MAAM,EACrB,sBAAsB,CAAC,EAAE,MAAM,GAC9B,IAAI;IAQP,OAAO,CAAC,eAAe;CAWxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAE/E"}
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { normalizeCookieAuthOptions } from './cookie-auth.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Describes the cookie options contract.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Describes the set cookie options contract.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Describes the cookie manager config contract.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Provides the default cookie options value.
|
|
17
|
+
*/
|
|
2
18
|
export const DEFAULT_COOKIE_OPTIONS = {
|
|
3
19
|
httpOnly: true,
|
|
4
20
|
secure: true,
|
|
@@ -35,6 +51,10 @@ function buildClearCookieHeader(name, options) {
|
|
|
35
51
|
maxAge: 0
|
|
36
52
|
});
|
|
37
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Represents the cookie manager.
|
|
57
|
+
*/
|
|
38
58
|
export class CookieManager {
|
|
39
59
|
options;
|
|
40
60
|
cookieOptions;
|
|
@@ -88,6 +108,13 @@ export class CookieManager {
|
|
|
88
108
|
response.setHeader('Set-Cookie', cookies.length === 1 ? cookies[0] : cookies);
|
|
89
109
|
}
|
|
90
110
|
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Create cookie manager.
|
|
114
|
+
*
|
|
115
|
+
* @param config The config.
|
|
116
|
+
* @returns The create cookie manager result.
|
|
117
|
+
*/
|
|
91
118
|
export function createCookieManager(config) {
|
|
92
119
|
return new CookieManager(config);
|
|
93
120
|
}
|
package/dist/decorators.d.ts
CHANGED
|
@@ -19,6 +19,26 @@ type ClassOrMethodDecoratorLike = StandardClassDecoratorFn & StandardMethodDecor
|
|
|
19
19
|
* @returns A class-or-method decorator that stores the auth requirement metadata.
|
|
20
20
|
*/
|
|
21
21
|
export declare function UseAuth(strategy: string): ClassOrMethodDecoratorLike;
|
|
22
|
+
/**
|
|
23
|
+
* Declares a strategy that may leave `requestContext.principal` unset when credentials are absent.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* Use this decorator only for routes that intentionally accept both authenticated and
|
|
27
|
+
* unauthenticated callers. Scope requirements still require a resolved principal.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* @UseOptionalAuth('cookie')
|
|
32
|
+
* @Get('/session')
|
|
33
|
+
* getSession(_input: unknown, ctx: RequestContext) {
|
|
34
|
+
* return { subject: ctx.principal?.subject ?? null };
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @param strategy Strategy name previously registered through `PassportModule.forRoot(...)`.
|
|
39
|
+
* @returns A class-or-method decorator that stores the optional auth requirement metadata.
|
|
40
|
+
*/
|
|
41
|
+
export declare function UseOptionalAuth(strategy: string): ClassOrMethodDecoratorLike;
|
|
22
42
|
/**
|
|
23
43
|
* Declares scope requirements that `AuthGuard` must enforce after authentication succeeds.
|
|
24
44
|
*
|
package/dist/decorators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AASA,KAAK,wBAAwB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,IAAI,CAAC;AAC1F,KAAK,yBAAyB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAC;AACjG,KAAK,0BAA0B,GAAG,wBAAwB,GAAG,yBAAyB,CAAC;AAyEvF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CAEpE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CAE5E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,0BAA0B,CAE7E"}
|
package/dist/decorators.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { ensureMetadataSymbol } from '@fluojs/core/internal';
|
|
1
2
|
import { UseGuards } from '@fluojs/http';
|
|
2
3
|
import { AuthGuard } from './guard.js';
|
|
3
4
|
import { getOwnAuthRequirement } from './metadata.js';
|
|
4
5
|
import { mergeAuthRequirements } from './scope.js';
|
|
5
6
|
const standardClassRequirementKey = Symbol.for('fluo.passport.standard.class-auth');
|
|
6
7
|
const standardMethodRequirementKey = Symbol.for('fluo.passport.standard.method-auth');
|
|
8
|
+
ensureMetadataSymbol();
|
|
7
9
|
function isStandardClassContext(context) {
|
|
8
10
|
return typeof context === 'object' && context !== null && 'kind' in context && context.kind === 'class';
|
|
9
11
|
}
|
|
@@ -70,6 +72,32 @@ export function UseAuth(strategy) {
|
|
|
70
72
|
});
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Declares a strategy that may leave `requestContext.principal` unset when credentials are absent.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* Use this decorator only for routes that intentionally accept both authenticated and
|
|
80
|
+
* unauthenticated callers. Scope requirements still require a resolved principal.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* @UseOptionalAuth('cookie')
|
|
85
|
+
* @Get('/session')
|
|
86
|
+
* getSession(_input: unknown, ctx: RequestContext) {
|
|
87
|
+
* return { subject: ctx.principal?.subject ?? null };
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @param strategy Strategy name previously registered through `PassportModule.forRoot(...)`.
|
|
92
|
+
* @returns A class-or-method decorator that stores the optional auth requirement metadata.
|
|
93
|
+
*/
|
|
94
|
+
export function UseOptionalAuth(strategy) {
|
|
95
|
+
return createAuthRequirementDecorator({
|
|
96
|
+
optional: true,
|
|
97
|
+
strategy
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
73
101
|
/**
|
|
74
102
|
* Declares scope requirements that `AuthGuard` must enforce after authentication succeeds.
|
|
75
103
|
*
|
package/dist/guard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAa5F,OAAO,KAAK,EACV,iBAAiB,
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAa5F,OAAO,KAAK,EACV,iBAAiB,EAKjB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAsFpB;;;;;;;;;GASG;AACH,qBACa,SAAU,YAAW,iBAAiB;IAE/C,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,UAAU,GAAE,oBAAyB,EACrC,OAAO,GAAE,qBAA0B;IAGtD;;;;;;;;;;;;;;;;;;;OAmBG;IACG,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAkExD"}
|
package/dist/guard.js
CHANGED
|
@@ -13,10 +13,16 @@ import { getAuthRequirement } from './metadata.js';
|
|
|
13
13
|
function isAuthHandledResult(result) {
|
|
14
14
|
return typeof result === 'object' && result !== null && 'handled' in result && result.handled === true;
|
|
15
15
|
}
|
|
16
|
+
function isAuthOptionalResult(result) {
|
|
17
|
+
return typeof result === 'object' && result !== null && 'authenticated' in result && result.authenticated === false;
|
|
18
|
+
}
|
|
16
19
|
function resolvePrincipal(result) {
|
|
17
20
|
if (isAuthHandledResult(result)) {
|
|
18
21
|
return result.principal;
|
|
19
22
|
}
|
|
23
|
+
if (isAuthOptionalResult(result)) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
20
26
|
return result;
|
|
21
27
|
}
|
|
22
28
|
function isRecord(value) {
|
|
@@ -131,6 +137,9 @@ class AuthGuard {
|
|
|
131
137
|
return true;
|
|
132
138
|
}
|
|
133
139
|
if (!principal) {
|
|
140
|
+
if (isAuthOptionalResult(result) && requirement?.optional && !requirement.scopes?.length) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
134
143
|
throw new AuthenticationFailedError('Authentication strategy did not return a principal.');
|
|
135
144
|
}
|
|
136
145
|
if (!isPrincipal(principal)) {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides the passport options value.
|
|
3
|
+
*/
|
|
1
4
|
export declare const PASSPORT_OPTIONS: unique symbol;
|
|
5
|
+
/**
|
|
6
|
+
* Provides the auth strategy registry value.
|
|
7
|
+
*/
|
|
2
8
|
export declare const AUTH_STRATEGY_REGISTRY: unique symbol;
|
|
3
9
|
//# sourceMappingURL=internal-tokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-tokens.d.ts","sourceRoot":"","sources":["../src/internal-tokens.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,gBAAgB,eAAmC,CAAC;AACjE,eAAO,MAAM,sBAAsB,eAAyC,CAAC"}
|
|
1
|
+
{"version":3,"file":"internal-tokens.d.ts","sourceRoot":"","sources":["../src/internal-tokens.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,gBAAgB,eAAmC,CAAC;AACjE;;GAEG;AACH,eAAO,MAAM,sBAAsB,eAAyC,CAAC"}
|
package/dist/internal-tokens.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
const PASSPORT_OPTIONS_KEY = 'fluo.passport.options';
|
|
2
2
|
const AUTH_STRATEGY_REGISTRY_KEY = 'fluo.passport.strategy-registry';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Provides the passport options value.
|
|
6
|
+
*/
|
|
3
7
|
export const PASSPORT_OPTIONS = Symbol.for(PASSPORT_OPTIONS_KEY);
|
|
8
|
+
/**
|
|
9
|
+
* Provides the auth strategy registry value.
|
|
10
|
+
*/
|
|
4
11
|
export const AUTH_STRATEGY_REGISTRY = Symbol.for(AUTH_STRATEGY_REGISTRY_KEY);
|
package/dist/metadata.d.ts
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
import { type MetadataPropertyKey } from '@fluojs/core';
|
|
2
2
|
import type { AuthRequirement } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Define auth requirement.
|
|
5
|
+
*
|
|
6
|
+
* @param target The target.
|
|
7
|
+
* @param requirement The requirement.
|
|
8
|
+
* @param propertyKey The property key.
|
|
9
|
+
*/
|
|
3
10
|
export declare function defineAuthRequirement(target: Function | object, requirement: AuthRequirement, propertyKey?: MetadataPropertyKey): void;
|
|
11
|
+
/**
|
|
12
|
+
* Get own auth requirement.
|
|
13
|
+
*
|
|
14
|
+
* @param target The target.
|
|
15
|
+
* @param propertyKey The property key.
|
|
16
|
+
* @returns The get own auth requirement result.
|
|
17
|
+
*/
|
|
4
18
|
export declare function getOwnAuthRequirement(target: Function | object, propertyKey?: MetadataPropertyKey): AuthRequirement | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Get auth requirement.
|
|
21
|
+
*
|
|
22
|
+
* @param controllerType The controller type.
|
|
23
|
+
* @param propertyKey The property key.
|
|
24
|
+
* @returns The get auth requirement result.
|
|
25
|
+
*/
|
|
5
26
|
export declare function getAuthRequirement(controllerType: Function, propertyKey?: MetadataPropertyKey): AuthRequirement | undefined;
|
|
6
27
|
//# sourceMappingURL=metadata.d.ts.map
|
package/dist/metadata.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAmElD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAkCtI;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,EAAE,WAAW,CAAC,EAAE,mBAAmB,GAAG,eAAe,GAAG,SAAS,CAM/H;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,cAAc,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,mBAAmB,GAAG,eAAe,GAAG,SAAS,CA6B3H"}
|
package/dist/metadata.js
CHANGED
|
@@ -11,11 +11,13 @@ function normalizeRequirement(requirement) {
|
|
|
11
11
|
return undefined;
|
|
12
12
|
}
|
|
13
13
|
const strategy = requirement.strategy;
|
|
14
|
+
const optional = requirement.optional;
|
|
14
15
|
const scopes = normalizeDeclaredScopes(requirement.scopes);
|
|
15
|
-
if (!strategy && !scopes) {
|
|
16
|
+
if (!strategy && !scopes && optional !== true) {
|
|
16
17
|
return undefined;
|
|
17
18
|
}
|
|
18
19
|
return {
|
|
20
|
+
optional,
|
|
19
21
|
scopes,
|
|
20
22
|
strategy
|
|
21
23
|
};
|
|
@@ -45,6 +47,14 @@ function getStandardMethodRequirement(target, propertyKey) {
|
|
|
45
47
|
const map = getStandardConstructorMetadataBag(target)?.[standardMethodRequirementKey];
|
|
46
48
|
return normalizeRequirement(map?.get(propertyKey));
|
|
47
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Define auth requirement.
|
|
53
|
+
*
|
|
54
|
+
* @param target The target.
|
|
55
|
+
* @param requirement The requirement.
|
|
56
|
+
* @param propertyKey The property key.
|
|
57
|
+
*/
|
|
48
58
|
export function defineAuthRequirement(target, requirement, propertyKey) {
|
|
49
59
|
const normalizedRequirement = normalizeRequirement(requirement);
|
|
50
60
|
if (propertyKey === undefined) {
|
|
@@ -72,12 +82,28 @@ export function defineAuthRequirement(target, requirement, propertyKey) {
|
|
|
72
82
|
invalidateRequirementCache(controllerType, propertyKey);
|
|
73
83
|
}
|
|
74
84
|
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get own auth requirement.
|
|
88
|
+
*
|
|
89
|
+
* @param target The target.
|
|
90
|
+
* @param propertyKey The property key.
|
|
91
|
+
* @returns The get own auth requirement result.
|
|
92
|
+
*/
|
|
75
93
|
export function getOwnAuthRequirement(target, propertyKey) {
|
|
76
94
|
if (propertyKey === undefined) {
|
|
77
95
|
return mergeAuthRequirements(classRequirementStore.get(target), getStandardClassRequirement(target));
|
|
78
96
|
}
|
|
79
97
|
return mergeAuthRequirements(methodRequirementStore.get(target)?.get(propertyKey), getStandardMethodRequirement(target, propertyKey));
|
|
80
98
|
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get auth requirement.
|
|
102
|
+
*
|
|
103
|
+
* @param controllerType The controller type.
|
|
104
|
+
* @param propertyKey The property key.
|
|
105
|
+
* @returns The get auth requirement result.
|
|
106
|
+
*/
|
|
81
107
|
export function getAuthRequirement(controllerType, propertyKey) {
|
|
82
108
|
if (propertyKey === undefined) {
|
|
83
109
|
if (mergedClassRequirementCache.has(controllerType)) {
|
package/dist/scope.d.ts
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import type { AuthRequirement } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Normalize declared scopes.
|
|
4
|
+
*
|
|
5
|
+
* @param scopes The scopes.
|
|
6
|
+
* @returns The normalize declared scopes result.
|
|
7
|
+
*/
|
|
2
8
|
export declare function normalizeDeclaredScopes(scopes: unknown): string[] | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Normalize principal scopes.
|
|
11
|
+
*
|
|
12
|
+
* @param claims The claims.
|
|
13
|
+
* @returns The normalize principal scopes result.
|
|
14
|
+
*/
|
|
3
15
|
export declare function normalizePrincipalScopes(claims: Record<string, unknown>): string[] | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Merge auth requirements.
|
|
18
|
+
*
|
|
19
|
+
* @param base The base.
|
|
20
|
+
* @param extra The extra.
|
|
21
|
+
* @returns The merge auth requirements result.
|
|
22
|
+
*/
|
|
4
23
|
export declare function mergeAuthRequirements(base: AuthRequirement | undefined, extra: AuthRequirement | undefined): AuthRequirement | undefined;
|
|
5
24
|
//# sourceMappingURL=scope.d.ts.map
|
package/dist/scope.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAoBlD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAO7E;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAW9F;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,eAAe,GAAG,SAAS,EACjC,KAAK,EAAE,eAAe,GAAG,SAAS,GACjC,eAAe,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAoBlD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAO7E;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAW9F;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,eAAe,GAAG,SAAS,EACjC,KAAK,EAAE,eAAe,GAAG,SAAS,GACjC,eAAe,GAAG,SAAS,CAuB7B"}
|
package/dist/scope.js
CHANGED
|
@@ -11,6 +11,13 @@ function normalizeScopeItems(items) {
|
|
|
11
11
|
}
|
|
12
12
|
return normalized.length > 0 ? normalized : undefined;
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Normalize declared scopes.
|
|
17
|
+
*
|
|
18
|
+
* @param scopes The scopes.
|
|
19
|
+
* @returns The normalize declared scopes result.
|
|
20
|
+
*/
|
|
14
21
|
export function normalizeDeclaredScopes(scopes) {
|
|
15
22
|
if (!Array.isArray(scopes)) {
|
|
16
23
|
return undefined;
|
|
@@ -18,6 +25,13 @@ export function normalizeDeclaredScopes(scopes) {
|
|
|
18
25
|
const scopeItems = scopes.filter(scope => typeof scope === 'string');
|
|
19
26
|
return normalizeScopeItems(scopeItems);
|
|
20
27
|
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Normalize principal scopes.
|
|
31
|
+
*
|
|
32
|
+
* @param claims The claims.
|
|
33
|
+
* @returns The normalize principal scopes result.
|
|
34
|
+
*/
|
|
21
35
|
export function normalizePrincipalScopes(claims) {
|
|
22
36
|
if (Array.isArray(claims.scopes)) {
|
|
23
37
|
const scopes = claims.scopes.filter(scope => typeof scope === 'string');
|
|
@@ -28,16 +42,26 @@ export function normalizePrincipalScopes(claims) {
|
|
|
28
42
|
}
|
|
29
43
|
return undefined;
|
|
30
44
|
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Merge auth requirements.
|
|
48
|
+
*
|
|
49
|
+
* @param base The base.
|
|
50
|
+
* @param extra The extra.
|
|
51
|
+
* @returns The merge auth requirements result.
|
|
52
|
+
*/
|
|
31
53
|
export function mergeAuthRequirements(base, extra) {
|
|
32
54
|
if (!base && !extra) {
|
|
33
55
|
return undefined;
|
|
34
56
|
}
|
|
35
57
|
const scopes = normalizeDeclaredScopes([...(base?.scopes ?? []), ...(extra?.scopes ?? [])]);
|
|
58
|
+
const optional = extra && Object.hasOwn(extra, 'optional') ? extra.optional : base?.optional === true && extra?.strategy ? false : base?.optional;
|
|
36
59
|
const strategy = extra?.strategy ?? base?.strategy;
|
|
37
|
-
if (!strategy && !scopes) {
|
|
60
|
+
if (!strategy && !scopes && optional !== true) {
|
|
38
61
|
return undefined;
|
|
39
62
|
}
|
|
40
63
|
return {
|
|
64
|
+
optional,
|
|
41
65
|
scopes,
|
|
42
66
|
strategy
|
|
43
67
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -4,16 +4,22 @@ import type { Guard, GuardContext, Principal } from '@fluojs/http';
|
|
|
4
4
|
export interface AuthRequirement {
|
|
5
5
|
/** Named strategy to resolve from the strategy registry. */
|
|
6
6
|
strategy?: string;
|
|
7
|
+
/** Allows the request to continue without a resolved principal. */
|
|
8
|
+
optional?: boolean;
|
|
7
9
|
/** Required scopes that must be present on the resolved principal. */
|
|
8
10
|
scopes?: string[];
|
|
9
11
|
}
|
|
12
|
+
/** Authentication result variant used when a route explicitly allows missing credentials. */
|
|
13
|
+
export interface AuthOptionalResult {
|
|
14
|
+
authenticated: false;
|
|
15
|
+
}
|
|
10
16
|
/** Authentication result variant used when a strategy fully handled the response. */
|
|
11
17
|
export interface AuthHandledResult {
|
|
12
18
|
handled: true;
|
|
13
19
|
principal?: Principal;
|
|
14
20
|
}
|
|
15
21
|
/** Return type of an `AuthStrategy.authenticate(...)` call. */
|
|
16
|
-
export type AuthStrategyResult = Principal | AuthHandledResult;
|
|
22
|
+
export type AuthStrategyResult = Principal | AuthHandledResult | AuthOptionalResult;
|
|
17
23
|
/** Strategy contract implemented by authentication adapters. */
|
|
18
24
|
export interface AuthStrategy {
|
|
19
25
|
authenticate(context: GuardContext): MaybePromise<AuthStrategyResult>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnE,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qFAAqF;AACrF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEnE,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,6FAA6F;AAC7F,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,KAAK,CAAC;CACtB;AAED,qFAAqF;AACrF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAEpF,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,CAAC,kBAAkB,CAAC,CAAC;CACvE;AAED,gEAAgE;AAChE,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;CAC5B;AAED,4DAA4D;AAC5D,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAEjF,yDAAyD;AACzD,MAAM,WAAW,qBAAqB;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,oDAAoD;AACpD,MAAM,WAAW,iBAAkB,SAAQ,KAAK;IAC9C,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"guard",
|
|
10
10
|
"strategy"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.0-beta.
|
|
12
|
+
"version": "1.0.0-beta.5",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@fluojs/
|
|
40
|
-
"@fluojs/
|
|
41
|
-
"@fluojs/
|
|
42
|
-
"@fluojs/
|
|
43
|
-
"@fluojs/runtime": "^1.0.0-beta.
|
|
39
|
+
"@fluojs/di": "^1.0.0-beta.6",
|
|
40
|
+
"@fluojs/http": "^1.0.0-beta.10",
|
|
41
|
+
"@fluojs/jwt": "^1.0.0-beta.2",
|
|
42
|
+
"@fluojs/core": "^1.0.0-beta.4",
|
|
43
|
+
"@fluojs/runtime": "^1.0.0-beta.11"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"vitest": "^3.2.4"
|