@fluojs/passport 1.0.0-beta.1 → 1.0.0-beta.2
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 +4 -0
- package/README.md +4 -0
- package/dist/adapters/passport-js.d.ts.map +1 -1
- package/dist/adapters/passport-js.js +15 -1
- package/dist/cookie/cookie-auth.d.ts.map +1 -1
- package/dist/cookie/cookie-auth.js +2 -0
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +33 -0
- package/package.json +3 -3
package/README.ko.md
CHANGED
|
@@ -83,6 +83,8 @@ const googleBridge = createPassportJsStrategyBridge('google', GoogleStrategy, {
|
|
|
83
83
|
});
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
브릿지는 각 Passport.js 전략 실행을 정확히 한 번만 정착(settle)시킵니다. 전략은 바인딩된 Passport 액션(`success`, `fail`, `redirect`, `pass`, `error`) 중 하나를 호출해야 하며, promise rejection 또는 액션 없이 완료된 promise는 요청을 미해결 상태로 두지 않고 인증 실패로 처리됩니다. 커스텀 `mapPrincipal` 함수는 비어 있지 않은 `subject`와 객체 형태의 `claims`를 포함한 유효한 fluo `Principal`을 반환해야 합니다.
|
|
87
|
+
|
|
86
88
|
### 쿠키 인증 프리셋
|
|
87
89
|
|
|
88
90
|
HTTP 쿠키에서 인증 정보를 읽는 애플리케이션이라면 `CookieAuthModule.forRoot(...)`를 사용합니다.
|
|
@@ -110,6 +112,8 @@ export class AuthModule {}
|
|
|
110
112
|
|
|
111
113
|
애플리케이션 모듈에서 cookie-auth 지원이 필요하면 `CookieAuthModule.forRoot(...)`를 `PassportModule.forRoot(...)`와 함께 import 하세요.
|
|
112
114
|
|
|
115
|
+
`CookieAuthStrategy`는 `@fluojs/jwt`가 정규화한 JWT principal 계약을 보존하며, `subject`, `claims`, `issuer`, `audience`, `roles`, `scopes`를 그대로 전달합니다.
|
|
116
|
+
|
|
113
117
|
### 리프레시 토큰 수명 주기
|
|
114
118
|
|
|
115
119
|
패키지에서 제공하는 `RefreshTokenStrategy`와 `RefreshTokenService`를 사용하여 안전한 토큰 로테이션 및 폐기 기능을 구현할 수 있습니다.
|
package/README.md
CHANGED
|
@@ -83,6 +83,8 @@ const googleBridge = createPassportJsStrategyBridge('google', GoogleStrategy, {
|
|
|
83
83
|
});
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
The bridge settles each Passport.js strategy execution exactly once. A strategy must call one of the bound Passport actions (`success`, `fail`, `redirect`, `pass`, or `error`); promise rejections and promise completion without an action become authentication failures instead of leaving the request unresolved. Custom `mapPrincipal` functions must return a valid fluo `Principal` with a non-empty `subject` and object `claims`.
|
|
87
|
+
|
|
86
88
|
### Cookie Auth Preset
|
|
87
89
|
|
|
88
90
|
Use `CookieAuthModule.forRoot(...)` when your app authenticates requests from HTTP cookies.
|
|
@@ -110,6 +112,8 @@ export class AuthModule {}
|
|
|
110
112
|
|
|
111
113
|
Import `CookieAuthModule.forRoot(...)` alongside `PassportModule.forRoot(...)` when you want cookie-auth support in an application module.
|
|
112
114
|
|
|
115
|
+
`CookieAuthStrategy` preserves the normalized JWT principal contract from `@fluojs/jwt`, including `subject`, `claims`, `issuer`, `audience`, `roles`, and `scopes`.
|
|
116
|
+
|
|
113
117
|
### Refresh Token Lifecycle
|
|
114
118
|
|
|
115
119
|
The package provides a built-in `RefreshTokenStrategy` and `RefreshTokenService` to handle secure token rotation and revocation.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passport-js.d.ts","sourceRoot":"","sources":["../../src/adapters/passport-js.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAU7F;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC5D;AAaD;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,iDAAiD;IACjD,OAAO,EAAE,YAAY,CAAC;IACtB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yDAAyD;IACzD,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,KAAK,EAAE,8BAA8B,KAAK,SAAS,CAAC;AAE7F;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,sEAAsE;IACtE,YAAY,CAAC,EAAE,yBAAyB,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,EAAE,wBAAwB,CAAC;CACpC;
|
|
1
|
+
{"version":3,"file":"passport-js.d.ts","sourceRoot":"","sources":["../../src/adapters/passport-js.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAU7F;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC5D;AAaD;;;GAGG;AACH,MAAM,WAAW,8BAA8B;IAC7C,iDAAiD;IACjD,OAAO,EAAE,YAAY,CAAC;IACtB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yDAAyD;IACzD,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,KAAK,EAAE,8BAA8B,KAAK,SAAS,CAAC;AAE7F;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,sEAAsE;IACtE,YAAY,CAAC,EAAE,yBAAyB,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,EAAE,wBAAwB,CAAC;CACpC;AAoGD;;;GAGG;AACH,qBAAa,sBAAuB,YAAW,YAAY;IAIvD,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuE;gBAGjF,gBAAgB,EAAE,sBAAsB,EACxC,OAAO,GAAE,6BAAkC;IAG9D,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,iBAAiB,CAAC;IAyC3E,OAAO,CAAC,wBAAwB;IAmBhC,OAAO,CAAC,MAAM;IAgBd,OAAO,CAAC,mBAAmB;IAqC3B,OAAO,CAAC,kBAAkB;CAS3B;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,KAAK,CAAC,sBAAsB,CAAC,EAC5C,OAAO,GAAE,6BAAkC,GAC1C,wBAAwB,CAwB1B"}
|
|
@@ -92,6 +92,9 @@ function cloneStrategyStateValue(value) {
|
|
|
92
92
|
}
|
|
93
93
|
return value;
|
|
94
94
|
}
|
|
95
|
+
function isPromiseLike(value) {
|
|
96
|
+
return typeof value === 'object' && value !== null && 'then' in value && typeof value.then === 'function';
|
|
97
|
+
}
|
|
95
98
|
|
|
96
99
|
/**
|
|
97
100
|
* A bridge strategy that allows using Passport.js strategies within the fluo
|
|
@@ -119,7 +122,18 @@ export class PassportJsAuthStrategy {
|
|
|
119
122
|
});
|
|
120
123
|
this.bindStrategyActions(strategy);
|
|
121
124
|
try {
|
|
122
|
-
strategy.authenticate(request, this.options.authenticateOptions);
|
|
125
|
+
const result = strategy.authenticate(request, this.options.authenticateOptions);
|
|
126
|
+
if (isPromiseLike(result)) {
|
|
127
|
+
result.then(() => {
|
|
128
|
+
this.settle(strategy, state => {
|
|
129
|
+
state.reject(new AuthenticationRequiredError('Passport strategy did not settle authentication.'));
|
|
130
|
+
});
|
|
131
|
+
}, error => {
|
|
132
|
+
this.settle(strategy, state => {
|
|
133
|
+
state.reject(error);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
123
137
|
} catch (error) {
|
|
124
138
|
this.settle(strategy, () => reject(error));
|
|
125
139
|
}
|
|
@@ -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,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEpE;;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;;GAEG;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;
|
|
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,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEpE;;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;;GAEG;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;CA+CvE;AAED;;GAEG;AACH,eAAO,MAAM,yBAAyB,WAAW,CAAC"}
|
|
@@ -77,7 +77,9 @@ class CookieAuthStrategy {
|
|
|
77
77
|
try {
|
|
78
78
|
const principal = await this.verifier.verifyAccessToken(accessToken);
|
|
79
79
|
return {
|
|
80
|
+
audience: principal.audience,
|
|
80
81
|
claims: principal.claims,
|
|
82
|
+
issuer: principal.issuer,
|
|
81
83
|
roles: principal.roles,
|
|
82
84
|
scopes: principal.scopes,
|
|
83
85
|
subject: principal.subject
|
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,EAIjB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,YAAY,CAAC;
|
|
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,EAIjB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AA8EpB;;;;;;;;;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;CA8DxD"}
|
package/dist/guard.js
CHANGED
|
@@ -19,6 +19,36 @@ function resolvePrincipal(result) {
|
|
|
19
19
|
}
|
|
20
20
|
return result;
|
|
21
21
|
}
|
|
22
|
+
function isRecord(value) {
|
|
23
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
function isStringArray(value) {
|
|
26
|
+
return Array.isArray(value) && value.every(item => typeof item === 'string');
|
|
27
|
+
}
|
|
28
|
+
function isPrincipal(value) {
|
|
29
|
+
if (!isRecord(value)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (typeof value.subject !== 'string' || value.subject.length === 0) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!isRecord(value.claims)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (value.issuer !== undefined && typeof value.issuer !== 'string') {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (value.audience !== undefined && typeof value.audience !== 'string' && !isStringArray(value.audience)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (value.roles !== undefined && !isStringArray(value.roles)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (value.scopes !== undefined && !isStringArray(value.scopes)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
22
52
|
function hasRequiredScopes(principal, scopes) {
|
|
23
53
|
return scopes.every(scope => principal.scopes?.includes(scope));
|
|
24
54
|
}
|
|
@@ -103,6 +133,9 @@ class AuthGuard {
|
|
|
103
133
|
if (!principal) {
|
|
104
134
|
throw new AuthenticationFailedError('Authentication strategy did not return a principal.');
|
|
105
135
|
}
|
|
136
|
+
if (!isPrincipal(principal)) {
|
|
137
|
+
throw new AuthenticationFailedError('Authentication strategy returned an invalid principal.');
|
|
138
|
+
}
|
|
106
139
|
if (requirement?.scopes?.length && !hasRequiredScopes(principal, requirement.scopes)) {
|
|
107
140
|
throw new ForbiddenException('Access denied.');
|
|
108
141
|
}
|
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.2",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@fluojs/core": "^1.0.0-beta.1",
|
|
40
|
-
"@fluojs/di": "^1.0.0-beta.
|
|
40
|
+
"@fluojs/di": "^1.0.0-beta.2",
|
|
41
41
|
"@fluojs/http": "^1.0.0-beta.1",
|
|
42
42
|
"@fluojs/jwt": "^1.0.0-beta.1",
|
|
43
|
-
"@fluojs/runtime": "^1.0.0-beta.
|
|
43
|
+
"@fluojs/runtime": "^1.0.0-beta.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"vitest": "^3.2.4"
|