@nya-account/node-sdk 2.0.1 → 2.0.3

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 CHANGED
@@ -23,24 +23,34 @@ const client = new NyaAccountClient({
23
23
  // See https://account.lolinya.net/docs/developer/service-endpoints#integration-endpoints
24
24
  issuer: 'https://account-api.edge.lolinya.net',
25
25
  clientId: 'my-app',
26
- clientSecret: 'my-secret',
26
+ clientSecret: 'my-secret'
27
27
  })
28
28
 
29
29
  // Create authorization URL (with PKCE)
30
30
  const { url, codeVerifier, state } = await client.createAuthorizationUrl({
31
31
  redirectUri: 'https://myapp.com/callback',
32
- scope: 'openid profile email',
32
+ scope: 'openid profile email'
33
33
  })
34
34
 
35
35
  // Exchange code for tokens
36
36
  const tokens = await client.exchangeCode({
37
37
  code: callbackCode,
38
38
  redirectUri: 'https://myapp.com/callback',
39
- codeVerifier,
39
+ codeVerifier
40
40
  })
41
41
 
42
42
  // Get user info
43
43
  const userInfo = await client.getUserInfo(tokens.accessToken)
44
+
45
+ // Revoke refresh token on logout
46
+ await client.revokeToken(tokens.refreshToken, { tokenTypeHint: 'refresh_token' })
47
+
48
+ // Build RP-initiated logout URL
49
+ const logoutUrl = await client.createEndSessionUrl({
50
+ idTokenHint: tokens.idToken,
51
+ postLogoutRedirectUri: 'https://myapp.com/logout/callback',
52
+ state: 'logout-csrf-state'
53
+ })
44
54
  ```
45
55
 
46
56
  ## Express Middleware
@@ -54,7 +64,7 @@ const app = express()
54
64
  const client = new NyaAccountClient({
55
65
  issuer: 'https://account-api.edge.lolinya.net',
56
66
  clientId: 'my-app',
57
- clientSecret: 'my-secret',
67
+ clientSecret: 'my-secret'
58
68
  })
59
69
 
60
70
  // Protect all /api routes
@@ -66,7 +76,8 @@ app.get('/api/me', (req, res) => {
66
76
  })
67
77
 
68
78
  // Require specific scopes
69
- app.get('/api/profile',
79
+ app.get(
80
+ '/api/profile',
70
81
  client.authenticate(),
71
82
  client.requireScopes('profile'),
72
83
  (req, res) => {
@@ -76,22 +87,19 @@ app.get('/api/profile',
76
87
  )
77
88
 
78
89
  // Use introspection for sensitive operations
79
- app.post('/api/sensitive',
80
- client.authenticate({ strategy: 'introspection' }),
81
- handler
82
- )
90
+ app.post('/api/sensitive', client.authenticate({ strategy: 'introspection' }), handler)
83
91
  ```
84
92
 
85
93
  ## Configuration
86
94
 
87
- | Option | Type | Default | Description |
88
- |---|---|---|---|
89
- | `issuer` | `string` | `'https://account-api.edge.lolinya.net'` | SSO service URL (Issuer URL). See [Service Endpoints](https://account.lolinya.net/docs/developer/service-endpoints#integration-endpoints) for available endpoints. |
90
- | `clientId` | `string` | *required* | OAuth client ID |
91
- | `clientSecret` | `string` | *required* | OAuth client secret |
92
- | `timeout` | `number` | `10000` | HTTP request timeout in milliseconds |
93
- | `discoveryCacheTtl` | `number` | `3600000` | Discovery document cache TTL in milliseconds (default: 1 hour) |
94
- | `endpoints` | `EndpointConfig` | — | Explicitly specify endpoint URLs (auto-discovered via OIDC Discovery if omitted) |
95
+ | Option | Type | Default | Description |
96
+ | ------------------- | ---------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
97
+ | `issuer` | `string` | `'https://account-api.edge.lolinya.net'` | SSO service URL (Issuer URL). See [Service Endpoints](https://account.lolinya.net/docs/developer/service-endpoints#integration-endpoints) for available endpoints. |
98
+ | `clientId` | `string` | _required_ | OAuth client ID |
99
+ | `clientSecret` | `string` | _required_ | OAuth client secret |
100
+ | `timeout` | `number` | `10000` | HTTP request timeout in milliseconds |
101
+ | `discoveryCacheTtl` | `number` | `3600000` | Discovery document cache TTL in milliseconds (default: 1 hour) |
102
+ | `endpoints` | `EndpointConfig` | — | Explicitly specify endpoint URLs (auto-discovered via OIDC Discovery if omitted) |
95
103
 
96
104
  ## API Reference
97
105
 
@@ -100,13 +108,15 @@ app.post('/api/sensitive',
100
108
  #### Authorization
101
109
 
102
110
  - **`createAuthorizationUrl(options)`** — Create an OAuth authorization URL with PKCE
111
+ - **`pushAuthorizationRequest(options)`** — Push authorization request to PAR endpoint (RFC 9126)
112
+ - **`createAuthorizationUrlWithPar(options)`** — Create authorization URL using PAR `request_uri`
103
113
 
104
114
  #### Token Operations
105
115
 
106
116
  - **`exchangeCode(options)`** — Exchange an authorization code for tokens
107
117
  - **`refreshToken(refreshToken)`** — Refresh an Access Token
108
- - **`revokeToken(token)`** — Revoke a token (RFC 7009)
109
- - **`introspectToken(token)`** — Token introspection (RFC 7662)
118
+ - **`revokeToken(token, options?)`** — Revoke a token (RFC 7009)
119
+ - **`introspectToken(token, options?)`** — Token introspection (RFC 7662)
110
120
 
111
121
  #### User Info
112
122
 
@@ -127,6 +137,10 @@ app.post('/api/sensitive',
127
137
  - **`discover()`** — Fetch OIDC Discovery document (cached with TTL)
128
138
  - **`clearCache()`** — Clear Discovery and JWT verifier cache
129
139
 
140
+ #### OIDC Logout
141
+
142
+ - **`createEndSessionUrl(options?)`** — Create OIDC RP-initiated logout URL (`end_session_endpoint`)
143
+
130
144
  ### Express Helpers
131
145
 
132
146
  Available from `@nya-account/node-sdk/express`:
@@ -147,17 +161,17 @@ The SDK provides typed error classes:
147
161
 
148
162
  ```typescript
149
163
  import {
150
- NyaAccountError, // Base error class
151
- OAuthError, // OAuth protocol errors from the server
164
+ NyaAccountError, // Base error class
165
+ OAuthError, // OAuth protocol errors from the server
152
166
  TokenVerificationError, // JWT verification failures
153
- DiscoveryError, // OIDC Discovery failures
167
+ DiscoveryError // OIDC Discovery failures
154
168
  } from '@nya-account/node-sdk'
155
169
 
156
170
  try {
157
171
  await client.verifyAccessToken(token)
158
172
  } catch (error) {
159
173
  if (error instanceof TokenVerificationError) {
160
- console.log(error.code) // 'token_verification_failed'
174
+ console.log(error.code) // 'token_verification_failed'
161
175
  console.log(error.description) // Human-readable description
162
176
  }
163
177
  }
@@ -9,6 +9,8 @@ declare const AccessTokenPayloadSchema: z.ZodObject<{
9
9
  aud: z.ZodString;
10
10
  scope: z.ZodString;
11
11
  ver: z.ZodString;
12
+ sid: z.ZodString;
13
+ sv: z.ZodNumber;
12
14
  iat: z.ZodNumber;
13
15
  exp: z.ZodNumber;
14
16
  jti: z.ZodString;
@@ -27,6 +29,8 @@ declare const AccessTokenPayloadSchema: z.ZodObject<{
27
29
  aud: string;
28
30
  iss: string;
29
31
  jti: string;
32
+ sid: string;
33
+ sv: number;
30
34
  ver: string;
31
35
  cnf?: {
32
36
  jkt: string;
@@ -39,6 +43,8 @@ declare const AccessTokenPayloadSchema: z.ZodObject<{
39
43
  aud: string;
40
44
  iss: string;
41
45
  jti: string;
46
+ sid: string;
47
+ sv: number;
42
48
  ver: string;
43
49
  cnf?: {
44
50
  jkt: string;
@@ -49,11 +55,11 @@ declare const IdTokenPayloadSchema: z.ZodObject<{
49
55
  iss: z.ZodString;
50
56
  sub: z.ZodString;
51
57
  aud: z.ZodString;
58
+ sid: z.ZodOptional<z.ZodString>;
52
59
  iat: z.ZodNumber;
53
60
  exp: z.ZodNumber;
54
61
  nonce: z.ZodOptional<z.ZodString>;
55
62
  name: z.ZodOptional<z.ZodString>;
56
- preferred_username: z.ZodOptional<z.ZodString>;
57
63
  email: z.ZodOptional<z.ZodString>;
58
64
  email_verified: z.ZodOptional<z.ZodBoolean>;
59
65
  updated_at: z.ZodOptional<z.ZodNumber>;
@@ -63,8 +69,8 @@ declare const IdTokenPayloadSchema: z.ZodObject<{
63
69
  sub: string;
64
70
  aud: string;
65
71
  iss: string;
72
+ sid?: string | undefined;
66
73
  name?: string | undefined;
67
- preferred_username?: string | undefined;
68
74
  email?: string | undefined;
69
75
  email_verified?: boolean | undefined;
70
76
  updated_at?: number | undefined;
@@ -75,8 +81,8 @@ declare const IdTokenPayloadSchema: z.ZodObject<{
75
81
  sub: string;
76
82
  aud: string;
77
83
  iss: string;
84
+ sid?: string | undefined;
78
85
  name?: string | undefined;
79
- preferred_username?: string | undefined;
80
86
  email?: string | undefined;
81
87
  email_verified?: boolean | undefined;
82
88
  updated_at?: number | undefined;
@@ -115,4 +121,4 @@ declare function sendOAuthError(res: Response, statusCode: number, error: string
115
121
 
116
122
  //#endregion
117
123
  export { AccessTokenPayload, IdTokenPayload, extractBearerToken as extractBearerToken$1, getAuth as getAuth$1, sendOAuthError as sendOAuthError$1 };
118
- //# sourceMappingURL=express-yO7hxKKd.d.ts.map
124
+ //# sourceMappingURL=express-Bn8IUnft.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express-Bn8IUnft.d.ts","names":[],"sources":["../src/core/schemas.d.ts","../src/middleware/express.d.ts"],"sourcesContent":null,"mappings":";;;;AAcA,IAAW,2BAAM;CAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;AAAA;AACjB,IAAW,qBAAqB;CAAC;CAAA,MAAA;CAAA,MAAA,EAAA;AAAA;AACjC,IAAG,uBAAA;CAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;AAAA;AACH,IAAW,iBAAa;CAAA;CAAA,MAAA;CAAA,MAAA,EAAA;AAAA;;;;;;;;;;;;;;;;;;;ACAxB,IAAW,UAAU,CAAC,GAAG,MAAM,kBAAmB;;;;AAQlD,IAAW,qBAAqB,CAAC,GAAG,MAAM,OAAQ;;;;AAIlD,IAAW,iBAAiB,CAAC,GAAG,MAAM,QAAS"}
package/dist/express.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { extractBearerToken$1 as extractBearerToken, getAuth$1 as getAuth, sendOAuthError$1 as sendOAuthError } from "./express-yO7hxKKd.js";
1
+ import { extractBearerToken$1 as extractBearerToken, getAuth$1 as getAuth, sendOAuthError$1 as sendOAuthError } from "./express-Bn8IUnft.js";
2
2
  export { extractBearerToken, getAuth, sendOAuthError };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AccessTokenPayload, IdTokenPayload, getAuth$1 as getAuth } from "./express-yO7hxKKd.js";
1
+ import { AccessTokenPayload, IdTokenPayload, getAuth$1 as getAuth } from "./express-Bn8IUnft.js";
2
2
  import { NextFunction, Request, Response } from "express";
3
3
 
4
4
  //#region src/core/types.d.ts
@@ -13,6 +13,8 @@ interface NyaAccountConfig {
13
13
  clientId: string;
14
14
  /** OAuth client secret */
15
15
  clientSecret: string;
16
+ /** Client authentication method for token endpoint (default: 'client_secret_post') */
17
+ tokenEndpointAuthMethod?: 'client_secret_post' | 'client_secret_basic';
16
18
  /** HTTP request timeout in milliseconds (default: 10000) */
17
19
  timeout?: number;
18
20
  /** Discovery document cache TTL in milliseconds (default: 3600000 = 1 hour) */
@@ -22,6 +24,7 @@ interface NyaAccountConfig {
22
24
  }
23
25
  interface EndpointConfig {
24
26
  authorization?: string;
27
+ pushedAuthorizationRequest?: string;
25
28
  token?: string;
26
29
  userinfo?: string;
27
30
  revocation?: string;
@@ -40,7 +43,6 @@ interface TokenResponse {
40
43
  interface UserInfo {
41
44
  sub: string;
42
45
  name?: string;
43
- preferredUsername?: string;
44
46
  picture?: string;
45
47
  email?: string;
46
48
  emailVerified?: boolean;
@@ -58,6 +60,8 @@ interface IntrospectionResponse {
58
60
  aud?: string;
59
61
  iss?: string;
60
62
  jti?: string;
63
+ sid?: string;
64
+ sv?: number;
61
65
  }
62
66
  interface DiscoveryDocument {
63
67
  issuer: string;
@@ -88,6 +92,20 @@ interface CreateAuthorizationUrlOptions {
88
92
  /** ID Token replay protection parameter */
89
93
  nonce?: string;
90
94
  }
95
+ interface PushAuthorizationRequestOptions extends CreateAuthorizationUrlOptions {
96
+ /** Optional JAR request object */
97
+ request?: string;
98
+ }
99
+ interface PushAuthorizationRequestResult {
100
+ /** PAR request URI */
101
+ requestUri: string;
102
+ /** PAR request URI lifetime in seconds */
103
+ expiresIn: number;
104
+ /** PKCE code_verifier, must be stored in session for later token exchange */
105
+ codeVerifier: string;
106
+ /** State parameter, must be stored in session for CSRF validation */
107
+ state: string;
108
+ }
91
109
  interface AuthorizationUrlResult {
92
110
  /** Full authorization URL to redirect the user to */
93
111
  url: string;
@@ -96,6 +114,16 @@ interface AuthorizationUrlResult {
96
114
  /** State parameter, must be stored in session for CSRF validation */
97
115
  state: string;
98
116
  }
117
+ interface CreateEndSessionUrlOptions {
118
+ /** Previously issued ID Token */
119
+ idTokenHint?: string;
120
+ /** Redirect URL after logout, must match registered post-logout URI */
121
+ postLogoutRedirectUri?: string;
122
+ /** Opaque state value returned to post_logout_redirect_uri */
123
+ state?: string;
124
+ /** Optional client ID override (defaults to configured clientId) */
125
+ clientId?: string;
126
+ }
99
127
  interface ExchangeCodeOptions {
100
128
  /** Authorization code received in the callback */
101
129
  code: string;
@@ -121,6 +149,18 @@ declare class NyaAccountClient {
121
149
  private readonly discoveryCacheTtl;
122
150
  private jwtVerifier;
123
151
  constructor(config: NyaAccountConfig);
152
+ /**
153
+ * 根据配置的认证方式返回请求体中的凭据参数
154
+ * client_secret_post: 凭据放入请求体
155
+ * client_secret_basic: 不放入请求体(通过 header 传递)
156
+ */
157
+ private getClientAuthBody;
158
+ /**
159
+ * 根据配置的认证方式返回请求头
160
+ * client_secret_basic: Authorization: Basic base64(client_id:client_secret)
161
+ * client_secret_post: 不添加额外头
162
+ */
163
+ private getClientAuthHeaders;
124
164
  /**
125
165
  * Fetch the OIDC Discovery document. Results are cached with a configurable TTL.
126
166
  */
@@ -136,6 +176,23 @@ declare class NyaAccountClient {
136
176
  * for later use in token exchange and CSRF validation.
137
177
  */
138
178
  createAuthorizationUrl(options: CreateAuthorizationUrlOptions): Promise<AuthorizationUrlResult>;
179
+ /**
180
+ * Push authorization parameters to PAR endpoint (RFC 9126).
181
+ *
182
+ * Returns a `request_uri` that can be used in the authorization endpoint.
183
+ */
184
+ pushAuthorizationRequest(options: PushAuthorizationRequestOptions): Promise<PushAuthorizationRequestResult>;
185
+ /**
186
+ * Create an authorization URL using PAR `request_uri`.
187
+ */
188
+ createAuthorizationUrlWithPar(options: PushAuthorizationRequestOptions): Promise<AuthorizationUrlResult & {
189
+ requestUri: string;
190
+ expiresIn: number;
191
+ }>;
192
+ /**
193
+ * Create OIDC RP-Initiated Logout URL (`end_session_endpoint`).
194
+ */
195
+ createEndSessionUrl(options?: CreateEndSessionUrlOptions): Promise<string>;
139
196
  /**
140
197
  * Exchange an authorization code for tokens (Authorization Code Grant).
141
198
  */
@@ -150,18 +207,22 @@ declare class NyaAccountClient {
150
207
  * Supports revoking Access Tokens or Refresh Tokens.
151
208
  * Revoking a Refresh Token also revokes its entire token family.
152
209
  */
153
- revokeToken(token: string): Promise<void>;
210
+ revokeToken(token: string, options?: {
211
+ tokenTypeHint?: 'access_token' | 'refresh_token';
212
+ }): Promise<void>;
154
213
  /**
155
214
  * Token introspection (RFC 7662).
156
215
  *
157
216
  * Query the server for the current state of a token (active status, associated user info, etc.).
158
217
  */
159
- introspectToken(token: string): Promise<IntrospectionResponse>;
218
+ introspectToken(token: string, options?: {
219
+ tokenTypeHint?: 'access_token' | 'refresh_token';
220
+ }): Promise<IntrospectionResponse>;
160
221
  /**
161
222
  * Get user info using an Access Token (OIDC UserInfo Endpoint).
162
223
  *
163
224
  * The returned fields depend on the scopes included in the token:
164
- * - `profile`: name, preferredUsername, picture, updatedAt
225
+ * - `profile`: name, picture, updatedAt
165
226
  * - `email`: email, emailVerified
166
227
  */
167
228
  getUserInfo(accessToken: string): Promise<UserInfo>;
@@ -271,5 +332,5 @@ declare function generateCodeChallenge(codeVerifier: string): string;
271
332
  declare function generatePkce(): PkcePair;
272
333
 
273
334
  //#endregion
274
- export { AccessTokenPayload, AuthenticateOptions, AuthorizationUrlResult, CreateAuthorizationUrlOptions, DiscoveryDocument, DiscoveryError, EndpointConfig, ExchangeCodeOptions, IdTokenPayload, IntrospectionResponse, NyaAccountClient, NyaAccountConfig, NyaAccountError, OAuthError, PkcePair, TokenResponse, TokenVerificationError, UserInfo, generateCodeChallenge, generateCodeVerifier, generatePkce, getAuth };
335
+ export { AccessTokenPayload, AuthenticateOptions, AuthorizationUrlResult, CreateAuthorizationUrlOptions, CreateEndSessionUrlOptions, DiscoveryDocument, DiscoveryError, EndpointConfig, ExchangeCodeOptions, IdTokenPayload, IntrospectionResponse, NyaAccountClient, NyaAccountConfig, NyaAccountError, OAuthError, PkcePair, PushAuthorizationRequestOptions, PushAuthorizationRequestResult, TokenResponse, TokenVerificationError, UserInfo, generateCodeChallenge, generateCodeVerifier, generatePkce, getAuth };
275
336
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/core/types.d.ts","../src/client.d.ts","../src/core/errors.d.ts","../src/utils/pkce.d.ts"],"sourcesContent":null,"mappings":";;;;AAEA,IAAW,mBAAmB,CAAC,IAAG,MAAA,cAAA;AAClC,IAAM,iBAAA,CAAA,EAAA;AACN,IAAW,gBAAgB,CAAC,EAAG;AAC/B,IAAK,WAAA,CAAA,EAAA;AACL,IAAW,wBAAwB,CAAC,EAAG;AACvC,IAAM,oBAAA,CAAA,EAAA;AACN,IAAW,gCAAQ,CAAA,EAAA;AACnB,IAAW,yBAAc,CAAA,EAAA;AACzB,IAAW,sBAAS,CAAA,EAAA;AACpB,IAAW,sBAAkB,CAAA,EAAA;AAC7B,IAAW,WAAW,CAAC,EAAC;;;;ACTxB,IAAW,mBAAmB;CAAC;CAAG,MAAI;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;AAAA;;;;;;;ACAtC,IAAW,kBAAkB,CAAC,IAAI,MAAM,KAAM;;;;AAI9C,IAAA,aAAA,CAAA,IAAA,MAAA,eAAA;;;;AAIA,IAAW,yBAAyB,CAAC,IAAI,MAAM,eAAS;;;;AAIxD,IAAW,iBAAc,CAAA,IAAA,MAAA,eAAA;;;;;;;ACXzB,IAAW,uBAAuB,CAAC,EAAG;;;;AAItC,IAAW,wBAAwB,CAAC,EAAG;;;;AAIvC,IAAW,eAAe,CAAC,IAAI,MAAM,QAAS"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/core/types.d.ts","../src/client.d.ts","../src/core/errors.d.ts","../src/utils/pkce.d.ts"],"sourcesContent":null,"mappings":";;;;AAEA,IAAW,mBAAmB,CAAC,IAAG,MAAA,cAAA;AAClC,IAAM,iBAAA,CAAA,EAAA;AACN,IAAW,gBAAgB,CAAC,EAAG;AAC/B,IAAK,WAAA,CAAA,EAAA;AACL,IAAW,wBAAwB,CAAC,EAAG;AACvC,IAAM,oBAAA,CAAA,EAAA;AACN,IAAW,gCAAQ,CAAA,EAAA;AACnB,IAAW,kCAAc,CAAA,IAAA,MAAA,6BAAA;AACzB,IAAW,iCAAS,CAAA,EAAA;AACpB,IAAW,yBAAkB,CAAA,EAAA;AAC7B,IAAW,6BAAa,CAAA,EAAA;AACxB,IAAW,sBAAsB,CAAC,EAAG;AACrC,IAAW,sBAAsB,CAAC,EAAG;AACrC,IAAW,WAAW,CAAC,EAAG;;;;ACZ1B,IAAW,mBAAmB;CAAC;CAAI,MAAG;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;CAAA,MAAA;AAAA;;;;;;;ACAtC,IAAW,kBAAkB,CAAC,IAAI,MAAM,KAAM;;;;AAI9C,IAAA,aAAA,CAAA,IAAA,MAAA,eAAA;;;;AAIA,IAAW,yBAAyB,CAAC,IAAI,MAAM,eAAS;;;;AAIxD,IAAW,iBAAc,CAAA,IAAA,MAAA,eAAA;;;;;;;ACXzB,IAAW,uBAAuB,CAAC,EAAG;;;;AAItC,IAAW,wBAAwB,CAAC,EAAG;;;;AAIvC,IAAW,eAAe,CAAC,IAAI,MAAM,QAAS"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { z } from "zod";
5
5
  import { createRemoteJWKSet, errors, jwtVerify } from "jose";
6
6
 
7
7
  //#region src/core/schemas.ts
8
+ const TokenTypeHintSchema = z.enum(["access_token", "refresh_token"]);
8
9
  const TokenResponseSchema = z.object({
9
10
  access_token: z.string(),
10
11
  token_type: z.string(),
@@ -28,12 +29,13 @@ const IntrospectionResponseSchema = z.object({
28
29
  sub: z.string().optional(),
29
30
  aud: z.string().optional(),
30
31
  iss: z.string().optional(),
31
- jti: z.string().optional()
32
+ jti: z.string().optional(),
33
+ sid: z.string().optional(),
34
+ sv: z.number().optional()
32
35
  });
33
36
  const UserInfoSchema = z.object({
34
37
  sub: z.string(),
35
38
  name: z.string().optional(),
36
- preferred_username: z.string().optional(),
37
39
  picture: z.string().optional(),
38
40
  email: z.string().optional(),
39
41
  email_verified: z.boolean().optional(),
@@ -61,12 +63,18 @@ const DiscoveryDocumentSchema = z.object({
61
63
  request_parameter_supported: z.boolean().optional(),
62
64
  request_uri_parameter_supported: z.boolean().optional()
63
65
  });
66
+ const PushedAuthorizationResponseSchema = z.object({
67
+ request_uri: z.string().min(1),
68
+ expires_in: z.number().int().positive()
69
+ });
64
70
  const AccessTokenPayloadSchema = z.object({
65
71
  iss: z.string(),
66
72
  sub: z.string(),
67
73
  aud: z.string(),
68
74
  scope: z.string(),
69
75
  ver: z.string(),
76
+ sid: z.string(),
77
+ sv: z.number().int().nonnegative(),
70
78
  iat: z.number(),
71
79
  exp: z.number(),
72
80
  jti: z.string(),
@@ -76,11 +84,11 @@ const IdTokenPayloadSchema = z.object({
76
84
  iss: z.string(),
77
85
  sub: z.string(),
78
86
  aud: z.string(),
87
+ sid: z.string().optional(),
79
88
  iat: z.number(),
80
89
  exp: z.number(),
81
90
  nonce: z.string().optional(),
82
91
  name: z.string().optional(),
83
- preferred_username: z.string().optional(),
84
92
  email: z.string().optional(),
85
93
  email_verified: z.boolean().optional(),
86
94
  updated_at: z.number().optional()
@@ -236,6 +244,7 @@ var JwtVerifier = class {
236
244
  //#region src/client.ts
237
245
  const DISCOVERY_ENDPOINT_MAP = {
238
246
  authorization: "authorizationEndpoint",
247
+ pushedAuthorizationRequest: "pushedAuthorizationRequestEndpoint",
239
248
  token: "tokenEndpoint",
240
249
  userinfo: "userinfoEndpoint",
241
250
  revocation: "revocationEndpoint",
@@ -264,6 +273,40 @@ var NyaAccountClient = class {
264
273
  }
265
274
  /**
266
275
 
276
+ * 根据配置的认证方式返回请求体中的凭据参数
277
+
278
+ * client_secret_post: 凭据放入请求体
279
+
280
+ * client_secret_basic: 不放入请求体(通过 header 传递)
281
+
282
+ */
283
+ getClientAuthBody() {
284
+ if (this.config.tokenEndpointAuthMethod === "client_secret_basic") return {};
285
+ return {
286
+ client_id: this.config.clientId,
287
+ client_secret: this.config.clientSecret
288
+ };
289
+ }
290
+ /**
291
+
292
+ * 根据配置的认证方式返回请求头
293
+
294
+ * client_secret_basic: Authorization: Basic base64(client_id:client_secret)
295
+
296
+ * client_secret_post: 不添加额外头
297
+
298
+ */
299
+ getClientAuthHeaders() {
300
+ if (this.config.tokenEndpointAuthMethod === "client_secret_basic") {
301
+ const encodedId = encodeURIComponent(this.config.clientId);
302
+ const encodedSecret = encodeURIComponent(this.config.clientSecret);
303
+ const credentials = Buffer.from(`${encodedId}:${encodedSecret}`).toString("base64");
304
+ return { Authorization: `Basic ${credentials}` };
305
+ }
306
+ return {};
307
+ }
308
+ /**
309
+
267
310
  * Fetch the OIDC Discovery document. Results are cached with a configurable TTL.
268
311
 
269
312
  */
@@ -344,6 +387,78 @@ var NyaAccountClient = class {
344
387
  }
345
388
  /**
346
389
 
390
+ * Push authorization parameters to PAR endpoint (RFC 9126).
391
+
392
+ *
393
+
394
+ * Returns a `request_uri` that can be used in the authorization endpoint.
395
+
396
+ */
397
+ async pushAuthorizationRequest(options) {
398
+ const parEndpoint = await this.resolveEndpoint("pushedAuthorizationRequest");
399
+ const codeVerifier = generateCodeVerifier();
400
+ const codeChallenge = generateCodeChallenge(codeVerifier);
401
+ const state = options.state ?? randomBytes(16).toString("base64url");
402
+ const payload = {
403
+ ...this.getClientAuthBody(),
404
+ redirect_uri: options.redirectUri,
405
+ response_type: "code",
406
+ scope: options.scope ?? "openid",
407
+ state,
408
+ code_challenge: codeChallenge,
409
+ code_challenge_method: "S256"
410
+ };
411
+ if (options.nonce) payload.nonce = options.nonce;
412
+ if (options.request) payload.request = options.request;
413
+ try {
414
+ const response = await this.httpClient.post(parEndpoint, payload, { headers: this.getClientAuthHeaders() });
415
+ const raw = PushedAuthorizationResponseSchema.parse(response.data);
416
+ return {
417
+ requestUri: raw.request_uri,
418
+ expiresIn: raw.expires_in,
419
+ codeVerifier,
420
+ state
421
+ };
422
+ } catch (error) {
423
+ throw this.handleTokenError(error);
424
+ }
425
+ }
426
+ /**
427
+
428
+ * Create an authorization URL using PAR `request_uri`.
429
+
430
+ */
431
+ async createAuthorizationUrlWithPar(options) {
432
+ const authorizationEndpoint = await this.resolveEndpoint("authorization");
433
+ const pushed = await this.pushAuthorizationRequest(options);
434
+ const params = new URLSearchParams({
435
+ client_id: this.config.clientId,
436
+ request_uri: pushed.requestUri
437
+ });
438
+ return {
439
+ url: `${authorizationEndpoint}?${params.toString()}`,
440
+ codeVerifier: pushed.codeVerifier,
441
+ state: pushed.state,
442
+ requestUri: pushed.requestUri,
443
+ expiresIn: pushed.expiresIn
444
+ };
445
+ }
446
+ /**
447
+
448
+ * Create OIDC RP-Initiated Logout URL (`end_session_endpoint`).
449
+
450
+ */
451
+ async createEndSessionUrl(options) {
452
+ const endSessionEndpoint = await this.resolveEndpoint("endSession");
453
+ const params = new URLSearchParams();
454
+ if (options?.idTokenHint) params.set("id_token_hint", options.idTokenHint);
455
+ if (options?.postLogoutRedirectUri) params.set("post_logout_redirect_uri", options.postLogoutRedirectUri);
456
+ if (options?.state) params.set("state", options.state);
457
+ params.set("client_id", options?.clientId ?? this.config.clientId);
458
+ return `${endSessionEndpoint}?${params.toString()}`;
459
+ }
460
+ /**
461
+
347
462
  * Exchange an authorization code for tokens (Authorization Code Grant).
348
463
 
349
464
  */
@@ -354,10 +469,9 @@ var NyaAccountClient = class {
354
469
  grant_type: "authorization_code",
355
470
  code: options.code,
356
471
  redirect_uri: options.redirectUri,
357
- client_id: this.config.clientId,
358
- client_secret: this.config.clientSecret,
359
- code_verifier: options.codeVerifier
360
- });
472
+ code_verifier: options.codeVerifier,
473
+ ...this.getClientAuthBody()
474
+ }, { headers: this.getClientAuthHeaders() });
361
475
  return this.mapTokenResponse(response.data);
362
476
  } catch (error) {
363
477
  throw this.handleTokenError(error);
@@ -374,9 +488,8 @@ var NyaAccountClient = class {
374
488
  const response = await this.httpClient.post(tokenEndpoint, {
375
489
  grant_type: "refresh_token",
376
490
  refresh_token: refreshToken,
377
- client_id: this.config.clientId,
378
- client_secret: this.config.clientSecret
379
- });
491
+ ...this.getClientAuthBody()
492
+ }, { headers: this.getClientAuthHeaders() });
380
493
  return this.mapTokenResponse(response.data);
381
494
  } catch (error) {
382
495
  throw this.handleTokenError(error);
@@ -393,14 +506,15 @@ var NyaAccountClient = class {
393
506
  * Revoking a Refresh Token also revokes its entire token family.
394
507
 
395
508
  */
396
- async revokeToken(token) {
509
+ async revokeToken(token, options) {
397
510
  const revocationEndpoint = await this.resolveEndpoint("revocation");
398
511
  try {
512
+ const tokenTypeHint = options?.tokenTypeHint ? TokenTypeHintSchema.parse(options.tokenTypeHint) : void 0;
399
513
  await this.httpClient.post(revocationEndpoint, {
400
514
  token,
401
- client_id: this.config.clientId,
402
- client_secret: this.config.clientSecret
403
- });
515
+ token_type_hint: tokenTypeHint,
516
+ ...this.getClientAuthBody()
517
+ }, { headers: this.getClientAuthHeaders() });
404
518
  } catch {}
405
519
  }
406
520
  /**
@@ -412,14 +526,15 @@ var NyaAccountClient = class {
412
526
  * Query the server for the current state of a token (active status, associated user info, etc.).
413
527
 
414
528
  */
415
- async introspectToken(token) {
529
+ async introspectToken(token, options) {
416
530
  const introspectionEndpoint = await this.resolveEndpoint("introspection");
417
531
  try {
532
+ const tokenTypeHint = options?.tokenTypeHint ? TokenTypeHintSchema.parse(options.tokenTypeHint) : void 0;
418
533
  const response = await this.httpClient.post(introspectionEndpoint, {
419
534
  token,
420
- client_id: this.config.clientId,
421
- client_secret: this.config.clientSecret
422
- });
535
+ token_type_hint: tokenTypeHint,
536
+ ...this.getClientAuthBody()
537
+ }, { headers: this.getClientAuthHeaders() });
423
538
  const raw = IntrospectionResponseSchema.parse(response.data);
424
539
  return {
425
540
  active: raw.active,
@@ -432,7 +547,9 @@ var NyaAccountClient = class {
432
547
  sub: raw.sub,
433
548
  aud: raw.aud,
434
549
  iss: raw.iss,
435
- jti: raw.jti
550
+ jti: raw.jti,
551
+ sid: raw.sid,
552
+ sv: raw.sv
436
553
  };
437
554
  } catch (error) {
438
555
  throw this.handleTokenError(error);
@@ -446,7 +563,7 @@ var NyaAccountClient = class {
446
563
 
447
564
  * The returned fields depend on the scopes included in the token:
448
565
 
449
- * - `profile`: name, preferredUsername, picture, updatedAt
566
+ * - `profile`: name, picture, updatedAt
450
567
 
451
568
  * - `email`: email, emailVerified
452
569
 
@@ -459,7 +576,6 @@ var NyaAccountClient = class {
459
576
  return {
460
577
  sub: raw.sub,
461
578
  name: raw.name,
462
- preferredUsername: raw.preferred_username,
463
579
  picture: raw.picture,
464
580
  email: raw.email,
465
581
  emailVerified: raw.email_verified,
@@ -558,6 +674,11 @@ var NyaAccountClient = class {
558
674
  sendOAuthError(res, 401, "invalid_token", "Token is not active");
559
675
  return;
560
676
  }
677
+ const tokenType = introspection.tokenType?.toLowerCase();
678
+ if (tokenType && tokenType !== "bearer" && tokenType !== "access_token") {
679
+ sendOAuthError(res, 401, "invalid_token", "Token is not an access token");
680
+ return;
681
+ }
561
682
  payload = {
562
683
  iss: introspection.iss ?? "",
563
684
  sub: introspection.sub ?? "",
@@ -566,7 +687,9 @@ var NyaAccountClient = class {
566
687
  ver: "1",
567
688
  iat: introspection.iat ?? 0,
568
689
  exp: introspection.exp ?? 0,
569
- jti: introspection.jti ?? ""
690
+ jti: introspection.jti ?? "",
691
+ sid: introspection.sid ?? "",
692
+ sv: introspection.sv ?? 0
570
693
  };
571
694
  } else payload = await this.verifyAccessToken(token);
572
695
  setAuth(req, payload);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["code: string","description: string","error: string","errorDescription: string","codeVerifier: string","jwksUri: string","issuer: string","defaultAudience: string","token: string","audience?: string","options?: { audience?: string; nonce?: string }","error: unknown","tokenType: string","DISCOVERY_ENDPOINT_MAP: Record<EndpointName, keyof DiscoveryDocument>","config: NyaAccountConfig","options: CreateAuthorizationUrlOptions","options: ExchangeCodeOptions","refreshToken: string","token: string","accessToken: string","options?: { audience?: string }","options?: { audience?: string; nonce?: string }","options?: AuthenticateOptions","req: Request","res: Response","next: NextFunction","payload: AccessTokenPayload","name: EndpointName","data: unknown","error: unknown"],"sources":["../src/core/schemas.ts","../src/core/errors.ts","../src/utils/pkce.ts","../src/utils/jwt.ts","../src/client.ts"],"sourcesContent":["import { z } from 'zod'\r\n\r\n// ============================================================\r\n// OAuth Token Response\r\n// ============================================================\r\n\r\nexport const TokenResponseSchema = z.object({\r\n access_token: z.string(),\r\n token_type: z.string(),\r\n expires_in: z.number(),\r\n refresh_token: z.string(),\r\n scope: z.string(),\r\n id_token: z.string().optional(),\r\n})\r\n\r\nexport type TokenResponseRaw = z.infer<typeof TokenResponseSchema>\r\n\r\n// ============================================================\r\n// OAuth Error Response\r\n// ============================================================\r\n\r\nexport const OAuthErrorSchema = z.object({\r\n error: z.string(),\r\n error_description: z.string().optional(),\r\n})\r\n\r\nexport type OAuthErrorRaw = z.infer<typeof OAuthErrorSchema>\r\n\r\n// ============================================================\r\n// Token Introspection Response (RFC 7662)\r\n// ============================================================\r\n\r\nexport const IntrospectionResponseSchema = z.object({\r\n active: z.boolean(),\r\n scope: z.string().optional(),\r\n client_id: z.string().optional(),\r\n username: z.string().optional(),\r\n token_type: z.string().optional(),\r\n exp: z.number().optional(),\r\n iat: z.number().optional(),\r\n sub: z.string().optional(),\r\n aud: z.string().optional(),\r\n iss: z.string().optional(),\r\n jti: z.string().optional(),\r\n})\r\n\r\nexport type IntrospectionResponseRaw = z.infer<typeof IntrospectionResponseSchema>\r\n\r\n// ============================================================\r\n// OIDC UserInfo Response\r\n// ============================================================\r\n\r\nexport const UserInfoSchema = z.object({\r\n sub: z.string(),\r\n name: z.string().optional(),\r\n preferred_username: z.string().optional(),\r\n picture: z.string().optional(),\r\n email: z.string().optional(),\r\n email_verified: z.boolean().optional(),\r\n updated_at: z.number().optional(),\r\n})\r\n\r\nexport type UserInfoRaw = z.infer<typeof UserInfoSchema>\r\n\r\n// ============================================================\r\n// OIDC Discovery Document\r\n// ============================================================\r\n\r\nexport const DiscoveryDocumentSchema = z.object({\r\n issuer: z.string(),\r\n authorization_endpoint: z.string(),\r\n token_endpoint: z.string(),\r\n userinfo_endpoint: z.string().optional(),\r\n jwks_uri: z.string(),\r\n revocation_endpoint: z.string().optional(),\r\n introspection_endpoint: z.string().optional(),\r\n pushed_authorization_request_endpoint: z.string().optional(),\r\n end_session_endpoint: z.string().optional(),\r\n response_types_supported: z.array(z.string()),\r\n grant_types_supported: z.array(z.string()),\r\n id_token_signing_alg_values_supported: z.array(z.string()),\r\n scopes_supported: z.array(z.string()),\r\n subject_types_supported: z.array(z.string()),\r\n token_endpoint_auth_methods_supported: z.array(z.string()),\r\n code_challenge_methods_supported: z.array(z.string()).optional(),\r\n claims_supported: z.array(z.string()).optional(),\r\n dpop_signing_alg_values_supported: z.array(z.string()).optional(),\r\n request_parameter_supported: z.boolean().optional(),\r\n request_uri_parameter_supported: z.boolean().optional(),\r\n})\r\n\r\nexport type DiscoveryDocumentRaw = z.infer<typeof DiscoveryDocumentSchema>\r\n\r\n// ============================================================\r\n// JWT Access Token Payload (RFC 9068)\r\n// ============================================================\r\n\r\nexport const AccessTokenPayloadSchema = z.object({\r\n iss: z.string(),\r\n sub: z.string(),\r\n aud: z.string(),\r\n scope: z.string(),\r\n ver: z.string(),\r\n iat: z.number(),\r\n exp: z.number(),\r\n jti: z.string(),\r\n cnf: z.object({ jkt: z.string() }).optional(),\r\n})\r\n\r\nexport type AccessTokenPayload = z.infer<typeof AccessTokenPayloadSchema>\r\n\r\n// ============================================================\r\n// JWT ID Token Payload (OIDC Core)\r\n// ============================================================\r\n\r\nexport const IdTokenPayloadSchema = z.object({\r\n iss: z.string(),\r\n sub: z.string(),\r\n aud: z.string(),\r\n iat: z.number(),\r\n exp: z.number(),\r\n nonce: z.string().optional(),\r\n name: z.string().optional(),\r\n preferred_username: z.string().optional(),\r\n email: z.string().optional(),\r\n email_verified: z.boolean().optional(),\r\n updated_at: z.number().optional(),\r\n})\r\n\r\nexport type IdTokenPayload = z.infer<typeof IdTokenPayloadSchema>\r\n","/**\r\n * Base error class for the SDK.\r\n */\r\nexport class NyaAccountError extends Error {\r\n readonly code: string\r\n readonly description: string\r\n\r\n constructor(code: string, description: string) {\r\n super(`[${code}] ${description}`)\r\n this.name = 'NyaAccountError'\r\n this.code = code\r\n this.description = description\r\n }\r\n}\r\n\r\n/**\r\n * OAuth protocol error (from server error / error_description response).\r\n */\r\nexport class OAuthError extends NyaAccountError {\r\n constructor(error: string, errorDescription: string) {\r\n super(error, errorDescription)\r\n this.name = 'OAuthError'\r\n }\r\n}\r\n\r\n/**\r\n * JWT verification error.\r\n */\r\nexport class TokenVerificationError extends NyaAccountError {\r\n constructor(description: string) {\r\n super('token_verification_failed', description)\r\n this.name = 'TokenVerificationError'\r\n }\r\n}\r\n\r\n/**\r\n * OIDC Discovery error.\r\n */\r\nexport class DiscoveryError extends NyaAccountError {\r\n constructor(description: string) {\r\n super('discovery_error', description)\r\n this.name = 'DiscoveryError'\r\n }\r\n}\r\n","import { randomBytes, createHash } from 'node:crypto'\r\nimport type { PkcePair } from '@/core/types'\r\n\r\n/**\r\n * Generate a PKCE code_verifier (43-128 character random string).\r\n */\r\nexport function generateCodeVerifier(): string {\r\n return randomBytes(32).toString('base64url')\r\n}\r\n\r\n/**\r\n * Generate an S256 code_challenge from a code_verifier.\r\n */\r\nexport function generateCodeChallenge(codeVerifier: string): string {\r\n return createHash('sha256').update(codeVerifier).digest('base64url')\r\n}\r\n\r\n/**\r\n * Generate a PKCE code_verifier and code_challenge pair.\r\n */\r\nexport function generatePkce(): PkcePair {\r\n const codeVerifier = generateCodeVerifier()\r\n const codeChallenge = generateCodeChallenge(codeVerifier)\r\n return { codeVerifier, codeChallenge }\r\n}\r\n","import { createRemoteJWKSet, jwtVerify, errors as joseErrors } from 'jose'\r\nimport {\r\n AccessTokenPayloadSchema,\r\n IdTokenPayloadSchema,\r\n type AccessTokenPayload,\r\n type IdTokenPayload,\r\n} from '@/core/schemas'\r\nimport { TokenVerificationError } from '@/core/errors'\r\n\r\n/**\r\n * JWT verifier using remote JWKS for signature verification.\r\n */\r\nexport class JwtVerifier {\r\n private jwks: ReturnType<typeof createRemoteJWKSet>\r\n private issuer: string\r\n private defaultAudience: string\r\n\r\n constructor(jwksUri: string, issuer: string, defaultAudience: string) {\r\n this.jwks = createRemoteJWKSet(new URL(jwksUri))\r\n this.issuer = issuer\r\n this.defaultAudience = defaultAudience\r\n }\r\n\r\n /**\r\n * Verify an OAuth 2.0 Access Token (JWT, RFC 9068).\r\n */\r\n async verifyAccessToken(token: string, audience?: string): Promise<AccessTokenPayload> {\r\n try {\r\n const { payload } = await jwtVerify(token, this.jwks, {\r\n algorithms: ['RS256'],\r\n issuer: this.issuer,\r\n audience: audience ?? this.defaultAudience,\r\n })\r\n return AccessTokenPayloadSchema.parse(payload)\r\n } catch (error) {\r\n throw this.wrapError(error, 'Access Token')\r\n }\r\n }\r\n\r\n /**\r\n * Verify an OIDC ID Token.\r\n */\r\n async verifyIdToken(token: string, options?: { audience?: string; nonce?: string }): Promise<IdTokenPayload> {\r\n try {\r\n const { payload } = await jwtVerify(token, this.jwks, {\r\n algorithms: ['RS256'],\r\n issuer: this.issuer,\r\n audience: options?.audience ?? this.defaultAudience,\r\n })\r\n\r\n const parsed = IdTokenPayloadSchema.parse(payload)\r\n\r\n if (options?.nonce !== undefined && parsed.nonce !== options.nonce) {\r\n throw new TokenVerificationError('ID Token nonce mismatch')\r\n }\r\n\r\n return parsed\r\n } catch (error) {\r\n if (error instanceof TokenVerificationError) {\r\n throw error\r\n }\r\n throw this.wrapError(error, 'ID Token')\r\n }\r\n }\r\n\r\n private wrapError(error: unknown, tokenType: string): TokenVerificationError {\r\n if (error instanceof TokenVerificationError) {\r\n return error\r\n }\r\n if (error instanceof joseErrors.JWTExpired) {\r\n return new TokenVerificationError(`${tokenType} has expired`)\r\n }\r\n if (error instanceof joseErrors.JWTClaimValidationFailed) {\r\n return new TokenVerificationError(`${tokenType} claim validation failed: ${error.message}`)\r\n }\r\n if (error instanceof joseErrors.JWSSignatureVerificationFailed) {\r\n return new TokenVerificationError(`${tokenType} signature verification failed`)\r\n }\r\n const message = error instanceof Error ? error.message : 'Unknown error'\r\n return new TokenVerificationError(`${tokenType} verification failed: ${message}`)\r\n }\r\n}\r\n","import axios, { AxiosError, type AxiosInstance } from 'axios'\r\nimport type { Request, Response, NextFunction } from 'express'\r\nimport { randomBytes } from 'node:crypto'\r\nimport {\r\n TokenResponseSchema,\r\n OAuthErrorSchema,\r\n IntrospectionResponseSchema,\r\n UserInfoSchema,\r\n DiscoveryDocumentSchema,\r\n type AccessTokenPayload,\r\n type IdTokenPayload,\r\n} from '@/core/schemas'\r\nimport type {\r\n NyaAccountConfig,\r\n TokenResponse,\r\n UserInfo,\r\n IntrospectionResponse,\r\n DiscoveryDocument,\r\n AuthorizationUrlResult,\r\n CreateAuthorizationUrlOptions,\r\n ExchangeCodeOptions,\r\n AuthenticateOptions,\r\n EndpointConfig,\r\n} from '@/core/types'\r\nimport { OAuthError, DiscoveryError, NyaAccountError } from '@/core/errors'\r\nimport { generateCodeVerifier, generateCodeChallenge } from '@/utils/pkce'\r\nimport { JwtVerifier } from '@/utils/jwt'\r\nimport { setAuth, getAuth, extractBearerToken, sendOAuthError } from '@/middleware/express'\r\n\r\ntype EndpointName = keyof EndpointConfig\r\n\r\nconst DISCOVERY_ENDPOINT_MAP: Record<EndpointName, keyof DiscoveryDocument> = {\r\n authorization: 'authorizationEndpoint',\r\n token: 'tokenEndpoint',\r\n userinfo: 'userinfoEndpoint',\r\n revocation: 'revocationEndpoint',\r\n introspection: 'introspectionEndpoint',\r\n jwks: 'jwksUri',\r\n endSession: 'endSessionEndpoint',\r\n}\r\n\r\n/** Default issuer URL */\r\nconst DEFAULT_ISSUER = 'https://account-api.edge.lolinya.net'\r\n\r\n/** Default discovery cache TTL: 1 hour */\r\nconst DEFAULT_DISCOVERY_CACHE_TTL = 3600000\r\n\r\n/**\r\n * Nya Account Node.js SDK client.\r\n *\r\n * Provides full OAuth 2.1 / OIDC flow support:\r\n * - Authorization Code + PKCE\r\n * - Token exchange / refresh / revocation / introspection\r\n * - Local JWT verification (via JWKS)\r\n * - OIDC UserInfo\r\n * - OIDC Discovery auto-discovery\r\n * - Express middleware (Bearer Token auth + scope validation)\r\n *\r\n * @example\r\n * ```typescript\r\n * const client = new NyaAccountClient({\r\n * issuer: 'https://account.example.com',\r\n * clientId: 'my-app',\r\n * clientSecret: 'my-secret',\r\n * })\r\n *\r\n * // Create authorization URL (with PKCE)\r\n * const { url, codeVerifier, state } = await client.createAuthorizationUrl({\r\n * redirectUri: 'https://myapp.com/callback',\r\n * scope: 'openid profile email',\r\n * })\r\n *\r\n * // Exchange code for tokens\r\n * const tokens = await client.exchangeCode({\r\n * code: callbackCode,\r\n * redirectUri: 'https://myapp.com/callback',\r\n * codeVerifier,\r\n * })\r\n *\r\n * // Get user info\r\n * const userInfo = await client.getUserInfo(tokens.accessToken)\r\n * ```\r\n */\r\ntype ResolvedConfig = NyaAccountConfig & { issuer: string }\r\n\r\nexport class NyaAccountClient {\r\n private httpClient: AxiosInstance\r\n private config: ResolvedConfig\r\n private discoveryCache: DiscoveryDocument | null = null\r\n private discoveryCacheTimestamp = 0\r\n private readonly discoveryCacheTtl: number\r\n private jwtVerifier: JwtVerifier | null = null\r\n\r\n constructor(config: NyaAccountConfig) {\r\n this.config = {\r\n ...config,\r\n issuer: config.issuer ?? DEFAULT_ISSUER,\r\n }\r\n this.discoveryCacheTtl = config.discoveryCacheTtl ?? DEFAULT_DISCOVERY_CACHE_TTL\r\n this.httpClient = axios.create({\r\n timeout: config.timeout ?? 10000,\r\n })\r\n }\r\n\r\n // ============================================================\r\n // OIDC Discovery\r\n // ============================================================\r\n\r\n /**\r\n * Fetch the OIDC Discovery document. Results are cached with a configurable TTL.\r\n */\r\n async discover(): Promise<DiscoveryDocument> {\r\n if (this.discoveryCache && Date.now() - this.discoveryCacheTimestamp < this.discoveryCacheTtl) {\r\n return this.discoveryCache\r\n }\r\n\r\n try {\r\n const url = `${this.config.issuer}/.well-known/openid-configuration`\r\n const response = await this.httpClient.get(url)\r\n const raw = DiscoveryDocumentSchema.parse(response.data)\r\n\r\n this.discoveryCache = {\r\n issuer: raw.issuer,\r\n authorizationEndpoint: raw.authorization_endpoint,\r\n tokenEndpoint: raw.token_endpoint,\r\n userinfoEndpoint: raw.userinfo_endpoint,\r\n jwksUri: raw.jwks_uri,\r\n revocationEndpoint: raw.revocation_endpoint,\r\n introspectionEndpoint: raw.introspection_endpoint,\r\n pushedAuthorizationRequestEndpoint: raw.pushed_authorization_request_endpoint,\r\n endSessionEndpoint: raw.end_session_endpoint,\r\n responseTypesSupported: raw.response_types_supported,\r\n grantTypesSupported: raw.grant_types_supported,\r\n idTokenSigningAlgValuesSupported: raw.id_token_signing_alg_values_supported,\r\n scopesSupported: raw.scopes_supported,\r\n subjectTypesSupported: raw.subject_types_supported,\r\n tokenEndpointAuthMethodsSupported: raw.token_endpoint_auth_methods_supported,\r\n codeChallengeMethodsSupported: raw.code_challenge_methods_supported,\r\n claimsSupported: raw.claims_supported,\r\n }\r\n this.discoveryCacheTimestamp = Date.now()\r\n\r\n return this.discoveryCache\r\n } catch (error) {\r\n if (error instanceof DiscoveryError) throw error\r\n const message = error instanceof Error ? error.message : 'Unknown error'\r\n throw new DiscoveryError(`Failed to fetch OIDC Discovery document: ${message}`)\r\n }\r\n }\r\n\r\n /**\r\n * Clear the cached Discovery document and JWT verifier, forcing a re-fetch on next use.\r\n */\r\n clearCache(): void {\r\n this.discoveryCache = null\r\n this.discoveryCacheTimestamp = 0\r\n this.jwtVerifier = null\r\n }\r\n\r\n // ============================================================\r\n // Authorization URL\r\n // ============================================================\r\n\r\n /**\r\n * Create an OAuth authorization URL (automatically includes PKCE).\r\n *\r\n * The returned `codeVerifier` and `state` must be saved to the session\r\n * for later use in token exchange and CSRF validation.\r\n */\r\n async createAuthorizationUrl(options: CreateAuthorizationUrlOptions): Promise<AuthorizationUrlResult> {\r\n const authorizationEndpoint = await this.resolveEndpoint('authorization')\r\n\r\n const codeVerifier = generateCodeVerifier()\r\n const codeChallenge = generateCodeChallenge(codeVerifier)\r\n const state = options.state ?? randomBytes(16).toString('base64url')\r\n\r\n const params = new URLSearchParams({\r\n client_id: this.config.clientId,\r\n redirect_uri: options.redirectUri,\r\n response_type: 'code',\r\n scope: options.scope ?? 'openid',\r\n state,\r\n code_challenge: codeChallenge,\r\n code_challenge_method: 'S256',\r\n })\r\n\r\n if (options.nonce) {\r\n params.set('nonce', options.nonce)\r\n }\r\n\r\n return {\r\n url: `${authorizationEndpoint}?${params.toString()}`,\r\n codeVerifier,\r\n state,\r\n }\r\n }\r\n\r\n // ============================================================\r\n // Token Operations\r\n // ============================================================\r\n\r\n /**\r\n * Exchange an authorization code for tokens (Authorization Code Grant).\r\n */\r\n async exchangeCode(options: ExchangeCodeOptions): Promise<TokenResponse> {\r\n const tokenEndpoint = await this.resolveEndpoint('token')\r\n\r\n try {\r\n const response = await this.httpClient.post(tokenEndpoint, {\r\n grant_type: 'authorization_code',\r\n code: options.code,\r\n redirect_uri: options.redirectUri,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n code_verifier: options.codeVerifier,\r\n })\r\n\r\n return this.mapTokenResponse(response.data)\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n /**\r\n * Refresh an Access Token using a Refresh Token.\r\n */\r\n async refreshToken(refreshToken: string): Promise<TokenResponse> {\r\n const tokenEndpoint = await this.resolveEndpoint('token')\r\n\r\n try {\r\n const response = await this.httpClient.post(tokenEndpoint, {\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n })\r\n\r\n return this.mapTokenResponse(response.data)\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n /**\r\n * Revoke a token (RFC 7009).\r\n *\r\n * Supports revoking Access Tokens or Refresh Tokens.\r\n * Revoking a Refresh Token also revokes its entire token family.\r\n */\r\n async revokeToken(token: string): Promise<void> {\r\n const revocationEndpoint = await this.resolveEndpoint('revocation')\r\n\r\n try {\r\n await this.httpClient.post(revocationEndpoint, {\r\n token,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n })\r\n } catch {\r\n // RFC 7009: revocation endpoint always returns 200, ignore errors\r\n }\r\n }\r\n\r\n /**\r\n * Token introspection (RFC 7662).\r\n *\r\n * Query the server for the current state of a token (active status, associated user info, etc.).\r\n */\r\n async introspectToken(token: string): Promise<IntrospectionResponse> {\r\n const introspectionEndpoint = await this.resolveEndpoint('introspection')\r\n\r\n try {\r\n const response = await this.httpClient.post(introspectionEndpoint, {\r\n token,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n })\r\n\r\n const raw = IntrospectionResponseSchema.parse(response.data)\r\n return {\r\n active: raw.active,\r\n scope: raw.scope,\r\n clientId: raw.client_id,\r\n username: raw.username,\r\n tokenType: raw.token_type,\r\n exp: raw.exp,\r\n iat: raw.iat,\r\n sub: raw.sub,\r\n aud: raw.aud,\r\n iss: raw.iss,\r\n jti: raw.jti,\r\n }\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n // ============================================================\r\n // OIDC UserInfo\r\n // ============================================================\r\n\r\n /**\r\n * Get user info using an Access Token (OIDC UserInfo Endpoint).\r\n *\r\n * The returned fields depend on the scopes included in the token:\r\n * - `profile`: name, preferredUsername, picture, updatedAt\r\n * - `email`: email, emailVerified\r\n */\r\n async getUserInfo(accessToken: string): Promise<UserInfo> {\r\n const userinfoEndpoint = await this.resolveEndpoint('userinfo')\r\n\r\n try {\r\n const response = await this.httpClient.get(userinfoEndpoint, {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n })\r\n\r\n const raw = UserInfoSchema.parse(response.data)\r\n return {\r\n sub: raw.sub,\r\n name: raw.name,\r\n preferredUsername: raw.preferred_username,\r\n picture: raw.picture,\r\n email: raw.email,\r\n emailVerified: raw.email_verified,\r\n updatedAt: raw.updated_at,\r\n }\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n // ============================================================\r\n // Local JWT Verification\r\n // ============================================================\r\n\r\n /**\r\n * Locally verify a JWT Access Token (RFC 9068).\r\n *\r\n * Uses remote JWKS for signature verification, and validates issuer, audience, expiry, etc.\r\n *\r\n * @param token JWT Access Token string\r\n * @param options.audience Custom audience validation value (defaults to clientId)\r\n */\r\n async verifyAccessToken(token: string, options?: { audience?: string }): Promise<AccessTokenPayload> {\r\n const verifier = await this.getJwtVerifier()\r\n return verifier.verifyAccessToken(token, options?.audience)\r\n }\r\n\r\n /**\r\n * Locally verify an OIDC ID Token.\r\n *\r\n * @param token JWT ID Token string\r\n * @param options.audience Custom audience validation value (defaults to clientId)\r\n * @param options.nonce Validate the nonce claim (required if nonce was sent during authorization)\r\n */\r\n async verifyIdToken(token: string, options?: { audience?: string; nonce?: string }): Promise<IdTokenPayload> {\r\n const verifier = await this.getJwtVerifier()\r\n return verifier.verifyIdToken(token, options)\r\n }\r\n\r\n // ============================================================\r\n // Express Middleware\r\n // ============================================================\r\n\r\n /**\r\n * Express middleware: verify the Bearer Token in the request.\r\n *\r\n * After successful verification, use `getAuth(req)` to retrieve the token payload.\r\n *\r\n * @param options.strategy Verification strategy: 'local' (default, JWT local verification) or 'introspection' (remote introspection)\r\n *\r\n * @example\r\n * ```typescript\r\n * import { getAuth } from '@nya-account/node-sdk/express'\r\n *\r\n * app.use('/api', client.authenticate())\r\n *\r\n * app.get('/api/me', (req, res) => {\r\n * const auth = getAuth(req)\r\n * res.json({ userId: auth?.sub })\r\n * })\r\n * ```\r\n */\r\n authenticate(options?: AuthenticateOptions): (req: Request, res: Response, next: NextFunction) => void {\r\n const strategy = options?.strategy ?? 'local'\r\n\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n const token = extractBearerToken(req)\r\n if (!token) {\r\n sendOAuthError(res, 401, 'invalid_token', 'Missing Bearer token in Authorization header')\r\n return\r\n }\r\n\r\n const handleVerification = async (): Promise<void> => {\r\n let payload: AccessTokenPayload\r\n\r\n if (strategy === 'introspection') {\r\n const introspection = await this.introspectToken(token)\r\n if (!introspection.active) {\r\n sendOAuthError(res, 401, 'invalid_token', 'Token is not active')\r\n return\r\n }\r\n payload = {\r\n iss: introspection.iss ?? '',\r\n sub: introspection.sub ?? '',\r\n aud: introspection.aud ?? '',\r\n scope: introspection.scope ?? '',\r\n ver: '1',\r\n iat: introspection.iat ?? 0,\r\n exp: introspection.exp ?? 0,\r\n jti: introspection.jti ?? '',\r\n }\r\n } else {\r\n payload = await this.verifyAccessToken(token)\r\n }\r\n\r\n setAuth(req, payload)\r\n next()\r\n }\r\n\r\n handleVerification().catch(() => {\r\n sendOAuthError(res, 401, 'invalid_token', 'Invalid or expired access token')\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Express middleware: validate that the token in the request contains the specified scopes.\r\n *\r\n * Must be used after the `authenticate()` middleware.\r\n *\r\n * @example\r\n * ```typescript\r\n * app.get('/api/profile',\r\n * client.authenticate(),\r\n * client.requireScopes('profile'),\r\n * (req, res) => { ... }\r\n * )\r\n * ```\r\n */\r\n requireScopes(...scopes: string[]): (req: Request, res: Response, next: NextFunction) => void {\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n const auth = getAuth(req)\r\n if (!auth) {\r\n sendOAuthError(res, 401, 'invalid_token', 'Request not authenticated')\r\n return\r\n }\r\n\r\n const tokenScopes = auth.scope.split(' ')\r\n const missingScopes = scopes.filter(s => !tokenScopes.includes(s))\r\n\r\n if (missingScopes.length > 0) {\r\n sendOAuthError(res, 403, 'insufficient_scope', `Missing required scopes: ${missingScopes.join(' ')}`)\r\n return\r\n }\r\n\r\n next()\r\n }\r\n }\r\n\r\n // ============================================================\r\n // Private Methods\r\n // ============================================================\r\n\r\n private async resolveEndpoint(name: EndpointName): Promise<string> {\r\n const explicit = this.config.endpoints?.[name]\r\n if (explicit) {\r\n return explicit\r\n }\r\n\r\n const discovery = await this.discover()\r\n const discoveryKey = DISCOVERY_ENDPOINT_MAP[name]\r\n const endpoint = discovery[discoveryKey]\r\n\r\n if (!endpoint || typeof endpoint !== 'string') {\r\n throw new NyaAccountError(\r\n 'endpoint_not_found',\r\n `Endpoint '${name}' not found in Discovery document`,\r\n )\r\n }\r\n\r\n return endpoint\r\n }\r\n\r\n private async getJwtVerifier(): Promise<JwtVerifier> {\r\n if (this.jwtVerifier) {\r\n return this.jwtVerifier\r\n }\r\n\r\n const jwksUri = await this.resolveEndpoint('jwks')\r\n const discovery = await this.discover()\r\n\r\n this.jwtVerifier = new JwtVerifier(jwksUri, discovery.issuer, this.config.clientId)\r\n return this.jwtVerifier\r\n }\r\n\r\n private mapTokenResponse(data: unknown): TokenResponse {\r\n const raw = TokenResponseSchema.parse(data)\r\n return {\r\n accessToken: raw.access_token,\r\n tokenType: raw.token_type,\r\n expiresIn: raw.expires_in,\r\n refreshToken: raw.refresh_token,\r\n scope: raw.scope,\r\n idToken: raw.id_token,\r\n }\r\n }\r\n\r\n private handleTokenError(error: unknown): NyaAccountError {\r\n if (error instanceof NyaAccountError) {\r\n return error\r\n }\r\n\r\n if (error instanceof AxiosError && error.response) {\r\n const parsed = OAuthErrorSchema.safeParse(error.response.data)\r\n if (parsed.success) {\r\n return new OAuthError(\r\n parsed.data.error,\r\n parsed.data.error_description ?? 'Unknown error',\r\n )\r\n }\r\n }\r\n\r\n const message = error instanceof Error ? error.message : 'Unknown error'\r\n return new NyaAccountError('request_failed', `Request failed: ${message}`)\r\n }\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["code: string","description: string","error: string","errorDescription: string","codeVerifier: string","jwksUri: string","issuer: string","defaultAudience: string","token: string","audience?: string","options?: { audience?: string; nonce?: string }","error: unknown","tokenType: string","DISCOVERY_ENDPOINT_MAP: Record<EndpointName, keyof DiscoveryDocument>","config: NyaAccountConfig","options: CreateAuthorizationUrlOptions","options: PushAuthorizationRequestOptions","payload: Record<string, string>","options?: CreateEndSessionUrlOptions","options: ExchangeCodeOptions","refreshToken: string","token: string","options?: { tokenTypeHint?: 'access_token' | 'refresh_token' }","accessToken: string","options?: { audience?: string }","options?: { audience?: string; nonce?: string }","options?: AuthenticateOptions","req: Request","res: Response","next: NextFunction","payload: AccessTokenPayload","name: EndpointName","data: unknown","error: unknown"],"sources":["../src/core/schemas.ts","../src/core/errors.ts","../src/utils/pkce.ts","../src/utils/jwt.ts","../src/client.ts"],"sourcesContent":["import { z } from 'zod'\r\n\r\nexport const TokenTypeHintSchema = z.enum(['access_token', 'refresh_token'])\r\n\r\n// ============================================================\r\n// OAuth Token Response\r\n// ============================================================\r\n\r\nexport const TokenResponseSchema = z.object({\r\n access_token: z.string(),\r\n token_type: z.string(),\r\n expires_in: z.number(),\r\n refresh_token: z.string(),\r\n scope: z.string(),\r\n id_token: z.string().optional()\r\n})\r\n\r\nexport type TokenResponseRaw = z.infer<typeof TokenResponseSchema>\r\n\r\n// ============================================================\r\n// OAuth Error Response\r\n// ============================================================\r\n\r\nexport const OAuthErrorSchema = z.object({\r\n error: z.string(),\r\n error_description: z.string().optional()\r\n})\r\n\r\nexport type OAuthErrorRaw = z.infer<typeof OAuthErrorSchema>\r\n\r\n// ============================================================\r\n// Token Introspection Response (RFC 7662)\r\n// ============================================================\r\n\r\nexport const IntrospectionResponseSchema = z.object({\r\n active: z.boolean(),\r\n scope: z.string().optional(),\r\n client_id: z.string().optional(),\r\n username: z.string().optional(),\r\n token_type: z.string().optional(),\r\n exp: z.number().optional(),\r\n iat: z.number().optional(),\r\n sub: z.string().optional(),\r\n aud: z.string().optional(),\r\n iss: z.string().optional(),\r\n jti: z.string().optional(),\r\n sid: z.string().optional(),\r\n sv: z.number().optional()\r\n})\r\n\r\nexport type IntrospectionResponseRaw = z.infer<typeof IntrospectionResponseSchema>\r\n\r\n// ============================================================\r\n// OIDC UserInfo Response\r\n// ============================================================\r\n\r\nexport const UserInfoSchema = z.object({\r\n sub: z.string(),\r\n name: z.string().optional(),\r\n picture: z.string().optional(),\r\n email: z.string().optional(),\r\n email_verified: z.boolean().optional(),\r\n updated_at: z.number().optional()\r\n})\r\n\r\nexport type UserInfoRaw = z.infer<typeof UserInfoSchema>\r\n\r\n// ============================================================\r\n// OIDC Discovery Document\r\n// ============================================================\r\n\r\nexport const DiscoveryDocumentSchema = z.object({\r\n issuer: z.string(),\r\n authorization_endpoint: z.string(),\r\n token_endpoint: z.string(),\r\n userinfo_endpoint: z.string().optional(),\r\n jwks_uri: z.string(),\r\n revocation_endpoint: z.string().optional(),\r\n introspection_endpoint: z.string().optional(),\r\n pushed_authorization_request_endpoint: z.string().optional(),\r\n end_session_endpoint: z.string().optional(),\r\n response_types_supported: z.array(z.string()),\r\n grant_types_supported: z.array(z.string()),\r\n id_token_signing_alg_values_supported: z.array(z.string()),\r\n scopes_supported: z.array(z.string()),\r\n subject_types_supported: z.array(z.string()),\r\n token_endpoint_auth_methods_supported: z.array(z.string()),\r\n code_challenge_methods_supported: z.array(z.string()).optional(),\r\n claims_supported: z.array(z.string()).optional(),\r\n dpop_signing_alg_values_supported: z.array(z.string()).optional(),\r\n request_parameter_supported: z.boolean().optional(),\r\n request_uri_parameter_supported: z.boolean().optional()\r\n})\r\n\r\nexport type DiscoveryDocumentRaw = z.infer<typeof DiscoveryDocumentSchema>\r\n\r\nexport const PushedAuthorizationResponseSchema = z.object({\r\n request_uri: z.string().min(1),\r\n expires_in: z.number().int().positive()\r\n})\r\n\r\nexport type PushedAuthorizationResponseRaw = z.infer<\r\n typeof PushedAuthorizationResponseSchema\r\n>\r\n\r\n// ============================================================\r\n// JWT Access Token Payload (RFC 9068)\r\n// ============================================================\r\n\r\nexport const AccessTokenPayloadSchema = z.object({\r\n iss: z.string(),\r\n sub: z.string(),\r\n aud: z.string(),\r\n scope: z.string(),\r\n ver: z.string(),\r\n sid: z.string(),\r\n sv: z.number().int().nonnegative(),\r\n iat: z.number(),\r\n exp: z.number(),\r\n jti: z.string(),\r\n cnf: z.object({ jkt: z.string() }).optional()\r\n})\r\n\r\nexport type AccessTokenPayload = z.infer<typeof AccessTokenPayloadSchema>\r\n\r\n// ============================================================\r\n// JWT ID Token Payload (OIDC Core)\r\n// ============================================================\r\n\r\nexport const IdTokenPayloadSchema = z.object({\r\n iss: z.string(),\r\n sub: z.string(),\r\n aud: z.string(),\r\n sid: z.string().optional(),\r\n iat: z.number(),\r\n exp: z.number(),\r\n nonce: z.string().optional(),\r\n name: z.string().optional(),\r\n email: z.string().optional(),\r\n email_verified: z.boolean().optional(),\r\n updated_at: z.number().optional()\r\n})\r\n\r\nexport type IdTokenPayload = z.infer<typeof IdTokenPayloadSchema>\r\n","/**\r\n * Base error class for the SDK.\r\n */\r\nexport class NyaAccountError extends Error {\r\n readonly code: string\r\n readonly description: string\r\n\r\n constructor(code: string, description: string) {\r\n super(`[${code}] ${description}`)\r\n this.name = 'NyaAccountError'\r\n this.code = code\r\n this.description = description\r\n }\r\n}\r\n\r\n/**\r\n * OAuth protocol error (from server error / error_description response).\r\n */\r\nexport class OAuthError extends NyaAccountError {\r\n constructor(error: string, errorDescription: string) {\r\n super(error, errorDescription)\r\n this.name = 'OAuthError'\r\n }\r\n}\r\n\r\n/**\r\n * JWT verification error.\r\n */\r\nexport class TokenVerificationError extends NyaAccountError {\r\n constructor(description: string) {\r\n super('token_verification_failed', description)\r\n this.name = 'TokenVerificationError'\r\n }\r\n}\r\n\r\n/**\r\n * OIDC Discovery error.\r\n */\r\nexport class DiscoveryError extends NyaAccountError {\r\n constructor(description: string) {\r\n super('discovery_error', description)\r\n this.name = 'DiscoveryError'\r\n }\r\n}\r\n","import { randomBytes, createHash } from 'node:crypto'\r\nimport type { PkcePair } from '@/core/types'\r\n\r\n/**\r\n * Generate a PKCE code_verifier (43-128 character random string).\r\n */\r\nexport function generateCodeVerifier(): string {\r\n return randomBytes(32).toString('base64url')\r\n}\r\n\r\n/**\r\n * Generate an S256 code_challenge from a code_verifier.\r\n */\r\nexport function generateCodeChallenge(codeVerifier: string): string {\r\n return createHash('sha256').update(codeVerifier).digest('base64url')\r\n}\r\n\r\n/**\r\n * Generate a PKCE code_verifier and code_challenge pair.\r\n */\r\nexport function generatePkce(): PkcePair {\r\n const codeVerifier = generateCodeVerifier()\r\n const codeChallenge = generateCodeChallenge(codeVerifier)\r\n return { codeVerifier, codeChallenge }\r\n}\r\n","import { createRemoteJWKSet, jwtVerify, errors as joseErrors } from 'jose'\r\nimport {\r\n AccessTokenPayloadSchema,\r\n IdTokenPayloadSchema,\r\n type AccessTokenPayload,\r\n type IdTokenPayload,\r\n} from '@/core/schemas'\r\nimport { TokenVerificationError } from '@/core/errors'\r\n\r\n/**\r\n * JWT verifier using remote JWKS for signature verification.\r\n */\r\nexport class JwtVerifier {\r\n private jwks: ReturnType<typeof createRemoteJWKSet>\r\n private issuer: string\r\n private defaultAudience: string\r\n\r\n constructor(jwksUri: string, issuer: string, defaultAudience: string) {\r\n this.jwks = createRemoteJWKSet(new URL(jwksUri))\r\n this.issuer = issuer\r\n this.defaultAudience = defaultAudience\r\n }\r\n\r\n /**\r\n * Verify an OAuth 2.0 Access Token (JWT, RFC 9068).\r\n */\r\n async verifyAccessToken(token: string, audience?: string): Promise<AccessTokenPayload> {\r\n try {\r\n const { payload } = await jwtVerify(token, this.jwks, {\r\n algorithms: ['RS256'],\r\n issuer: this.issuer,\r\n audience: audience ?? this.defaultAudience,\r\n })\r\n return AccessTokenPayloadSchema.parse(payload)\r\n } catch (error) {\r\n throw this.wrapError(error, 'Access Token')\r\n }\r\n }\r\n\r\n /**\r\n * Verify an OIDC ID Token.\r\n */\r\n async verifyIdToken(token: string, options?: { audience?: string; nonce?: string }): Promise<IdTokenPayload> {\r\n try {\r\n const { payload } = await jwtVerify(token, this.jwks, {\r\n algorithms: ['RS256'],\r\n issuer: this.issuer,\r\n audience: options?.audience ?? this.defaultAudience,\r\n })\r\n\r\n const parsed = IdTokenPayloadSchema.parse(payload)\r\n\r\n if (options?.nonce !== undefined && parsed.nonce !== options.nonce) {\r\n throw new TokenVerificationError('ID Token nonce mismatch')\r\n }\r\n\r\n return parsed\r\n } catch (error) {\r\n if (error instanceof TokenVerificationError) {\r\n throw error\r\n }\r\n throw this.wrapError(error, 'ID Token')\r\n }\r\n }\r\n\r\n private wrapError(error: unknown, tokenType: string): TokenVerificationError {\r\n if (error instanceof TokenVerificationError) {\r\n return error\r\n }\r\n if (error instanceof joseErrors.JWTExpired) {\r\n return new TokenVerificationError(`${tokenType} has expired`)\r\n }\r\n if (error instanceof joseErrors.JWTClaimValidationFailed) {\r\n return new TokenVerificationError(`${tokenType} claim validation failed: ${error.message}`)\r\n }\r\n if (error instanceof joseErrors.JWSSignatureVerificationFailed) {\r\n return new TokenVerificationError(`${tokenType} signature verification failed`)\r\n }\r\n const message = error instanceof Error ? error.message : 'Unknown error'\r\n return new TokenVerificationError(`${tokenType} verification failed: ${message}`)\r\n }\r\n}\r\n","import axios, { AxiosError, type AxiosInstance } from 'axios'\r\nimport type { Request, Response, NextFunction } from 'express'\r\nimport { randomBytes } from 'node:crypto'\r\nimport {\r\n TokenResponseSchema,\r\n OAuthErrorSchema,\r\n IntrospectionResponseSchema,\r\n UserInfoSchema,\r\n DiscoveryDocumentSchema,\r\n PushedAuthorizationResponseSchema,\r\n TokenTypeHintSchema,\r\n type AccessTokenPayload,\r\n type IdTokenPayload\r\n} from '@/core/schemas'\r\nimport type {\r\n NyaAccountConfig,\r\n TokenResponse,\r\n UserInfo,\r\n IntrospectionResponse,\r\n DiscoveryDocument,\r\n AuthorizationUrlResult,\r\n CreateAuthorizationUrlOptions,\r\n PushAuthorizationRequestOptions,\r\n PushAuthorizationRequestResult,\r\n CreateEndSessionUrlOptions,\r\n ExchangeCodeOptions,\r\n AuthenticateOptions,\r\n EndpointConfig\r\n} from '@/core/types'\r\nimport { OAuthError, DiscoveryError, NyaAccountError } from '@/core/errors'\r\nimport { generateCodeVerifier, generateCodeChallenge } from '@/utils/pkce'\r\nimport { JwtVerifier } from '@/utils/jwt'\r\nimport {\r\n setAuth,\r\n getAuth,\r\n extractBearerToken,\r\n sendOAuthError\r\n} from '@/middleware/express'\r\n\r\ntype EndpointName = keyof EndpointConfig\r\n\r\nconst DISCOVERY_ENDPOINT_MAP: Record<EndpointName, keyof DiscoveryDocument> = {\r\n authorization: 'authorizationEndpoint',\r\n pushedAuthorizationRequest: 'pushedAuthorizationRequestEndpoint',\r\n token: 'tokenEndpoint',\r\n userinfo: 'userinfoEndpoint',\r\n revocation: 'revocationEndpoint',\r\n introspection: 'introspectionEndpoint',\r\n jwks: 'jwksUri',\r\n endSession: 'endSessionEndpoint'\r\n}\r\n\r\n/** Default issuer URL */\r\nconst DEFAULT_ISSUER = 'https://account-api.edge.lolinya.net'\r\n\r\n/** Default discovery cache TTL: 1 hour */\r\nconst DEFAULT_DISCOVERY_CACHE_TTL = 3600000\r\n\r\n/**\r\n * Nya Account Node.js SDK client.\r\n *\r\n * Provides full OAuth 2.1 / OIDC flow support:\r\n * - Authorization Code + PKCE\r\n * - Token exchange / refresh / revocation / introspection\r\n * - Local JWT verification (via JWKS)\r\n * - OIDC UserInfo\r\n * - OIDC Discovery auto-discovery\r\n * - Express middleware (Bearer Token auth + scope validation)\r\n *\r\n * @example\r\n * ```typescript\r\n * const client = new NyaAccountClient({\r\n * issuer: 'https://account.example.com',\r\n * clientId: 'my-app',\r\n * clientSecret: 'my-secret',\r\n * })\r\n *\r\n * // Create authorization URL (with PKCE)\r\n * const { url, codeVerifier, state } = await client.createAuthorizationUrl({\r\n * redirectUri: 'https://myapp.com/callback',\r\n * scope: 'openid profile email',\r\n * })\r\n *\r\n * // Exchange code for tokens\r\n * const tokens = await client.exchangeCode({\r\n * code: callbackCode,\r\n * redirectUri: 'https://myapp.com/callback',\r\n * codeVerifier,\r\n * })\r\n *\r\n * // Get user info\r\n * const userInfo = await client.getUserInfo(tokens.accessToken)\r\n * ```\r\n */\r\ntype ResolvedConfig = NyaAccountConfig & { issuer: string }\r\n\r\nexport class NyaAccountClient {\r\n private httpClient: AxiosInstance\r\n private config: ResolvedConfig\r\n private discoveryCache: DiscoveryDocument | null = null\r\n private discoveryCacheTimestamp = 0\r\n private readonly discoveryCacheTtl: number\r\n private jwtVerifier: JwtVerifier | null = null\r\n\r\n constructor(config: NyaAccountConfig) {\r\n this.config = {\r\n ...config,\r\n issuer: config.issuer ?? DEFAULT_ISSUER\r\n }\r\n this.discoveryCacheTtl = config.discoveryCacheTtl ?? DEFAULT_DISCOVERY_CACHE_TTL\r\n this.httpClient = axios.create({\r\n timeout: config.timeout ?? 10000\r\n })\r\n }\r\n\r\n // ============================================================\r\n // Client Authentication Helpers\r\n // ============================================================\r\n\r\n /**\r\n * 根据配置的认证方式返回请求体中的凭据参数\r\n * client_secret_post: 凭据放入请求体\r\n * client_secret_basic: 不放入请求体(通过 header 传递)\r\n */\r\n private getClientAuthBody(): Record<string, string> {\r\n if (this.config.tokenEndpointAuthMethod === 'client_secret_basic') {\r\n return {}\r\n }\r\n return {\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret\r\n }\r\n }\r\n\r\n /**\r\n * 根据配置的认证方式返回请求头\r\n * client_secret_basic: Authorization: Basic base64(client_id:client_secret)\r\n * client_secret_post: 不添加额外头\r\n */\r\n private getClientAuthHeaders(): Record<string, string> {\r\n if (this.config.tokenEndpointAuthMethod === 'client_secret_basic') {\r\n // RFC 6749 Appendix B: 凭据需先进行 URL 编码再 Base64\r\n const encodedId = encodeURIComponent(this.config.clientId)\r\n const encodedSecret = encodeURIComponent(this.config.clientSecret)\r\n const credentials = Buffer.from(`${encodedId}:${encodedSecret}`).toString('base64')\r\n return { Authorization: `Basic ${credentials}` }\r\n }\r\n return {}\r\n }\r\n\r\n // ============================================================\r\n // OIDC Discovery\r\n // ============================================================\r\n\r\n /**\r\n * Fetch the OIDC Discovery document. Results are cached with a configurable TTL.\r\n */\r\n async discover(): Promise<DiscoveryDocument> {\r\n if (\r\n this.discoveryCache &&\r\n Date.now() - this.discoveryCacheTimestamp < this.discoveryCacheTtl\r\n ) {\r\n return this.discoveryCache\r\n }\r\n\r\n try {\r\n const url = `${this.config.issuer}/.well-known/openid-configuration`\r\n const response = await this.httpClient.get(url)\r\n const raw = DiscoveryDocumentSchema.parse(response.data)\r\n\r\n this.discoveryCache = {\r\n issuer: raw.issuer,\r\n authorizationEndpoint: raw.authorization_endpoint,\r\n tokenEndpoint: raw.token_endpoint,\r\n userinfoEndpoint: raw.userinfo_endpoint,\r\n jwksUri: raw.jwks_uri,\r\n revocationEndpoint: raw.revocation_endpoint,\r\n introspectionEndpoint: raw.introspection_endpoint,\r\n pushedAuthorizationRequestEndpoint:\r\n raw.pushed_authorization_request_endpoint,\r\n endSessionEndpoint: raw.end_session_endpoint,\r\n responseTypesSupported: raw.response_types_supported,\r\n grantTypesSupported: raw.grant_types_supported,\r\n idTokenSigningAlgValuesSupported:\r\n raw.id_token_signing_alg_values_supported,\r\n scopesSupported: raw.scopes_supported,\r\n subjectTypesSupported: raw.subject_types_supported,\r\n tokenEndpointAuthMethodsSupported:\r\n raw.token_endpoint_auth_methods_supported,\r\n codeChallengeMethodsSupported: raw.code_challenge_methods_supported,\r\n claimsSupported: raw.claims_supported\r\n }\r\n this.discoveryCacheTimestamp = Date.now()\r\n\r\n return this.discoveryCache\r\n } catch (error) {\r\n if (error instanceof DiscoveryError) throw error\r\n const message = error instanceof Error ? error.message : 'Unknown error'\r\n throw new DiscoveryError(\r\n `Failed to fetch OIDC Discovery document: ${message}`\r\n )\r\n }\r\n }\r\n\r\n /**\r\n * Clear the cached Discovery document and JWT verifier, forcing a re-fetch on next use.\r\n */\r\n clearCache(): void {\r\n this.discoveryCache = null\r\n this.discoveryCacheTimestamp = 0\r\n this.jwtVerifier = null\r\n }\r\n\r\n // ============================================================\r\n // Authorization URL\r\n // ============================================================\r\n\r\n /**\r\n * Create an OAuth authorization URL (automatically includes PKCE).\r\n *\r\n * The returned `codeVerifier` and `state` must be saved to the session\r\n * for later use in token exchange and CSRF validation.\r\n */\r\n async createAuthorizationUrl(\r\n options: CreateAuthorizationUrlOptions\r\n ): Promise<AuthorizationUrlResult> {\r\n const authorizationEndpoint = await this.resolveEndpoint('authorization')\r\n\r\n const codeVerifier = generateCodeVerifier()\r\n const codeChallenge = generateCodeChallenge(codeVerifier)\r\n const state = options.state ?? randomBytes(16).toString('base64url')\r\n\r\n const params = new URLSearchParams({\r\n client_id: this.config.clientId,\r\n redirect_uri: options.redirectUri,\r\n response_type: 'code',\r\n scope: options.scope ?? 'openid',\r\n state,\r\n code_challenge: codeChallenge,\r\n code_challenge_method: 'S256'\r\n })\r\n\r\n if (options.nonce) {\r\n params.set('nonce', options.nonce)\r\n }\r\n\r\n return {\r\n url: `${authorizationEndpoint}?${params.toString()}`,\r\n codeVerifier,\r\n state\r\n }\r\n }\r\n\r\n /**\r\n * Push authorization parameters to PAR endpoint (RFC 9126).\r\n *\r\n * Returns a `request_uri` that can be used in the authorization endpoint.\r\n */\r\n async pushAuthorizationRequest(\r\n options: PushAuthorizationRequestOptions\r\n ): Promise<PushAuthorizationRequestResult> {\r\n const parEndpoint = await this.resolveEndpoint('pushedAuthorizationRequest')\r\n\r\n const codeVerifier = generateCodeVerifier()\r\n const codeChallenge = generateCodeChallenge(codeVerifier)\r\n const state = options.state ?? randomBytes(16).toString('base64url')\r\n\r\n const payload: Record<string, string> = {\r\n ...this.getClientAuthBody(),\r\n redirect_uri: options.redirectUri,\r\n response_type: 'code',\r\n scope: options.scope ?? 'openid',\r\n state,\r\n code_challenge: codeChallenge,\r\n code_challenge_method: 'S256'\r\n }\r\n\r\n if (options.nonce) {\r\n payload.nonce = options.nonce\r\n }\r\n if (options.request) {\r\n payload.request = options.request\r\n }\r\n\r\n try {\r\n const response = await this.httpClient.post(parEndpoint, payload, {\r\n headers: this.getClientAuthHeaders()\r\n })\r\n const raw = PushedAuthorizationResponseSchema.parse(response.data)\r\n\r\n return {\r\n requestUri: raw.request_uri,\r\n expiresIn: raw.expires_in,\r\n codeVerifier,\r\n state\r\n }\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n /**\r\n * Create an authorization URL using PAR `request_uri`.\r\n */\r\n async createAuthorizationUrlWithPar(\r\n options: PushAuthorizationRequestOptions\r\n ): Promise<AuthorizationUrlResult & { requestUri: string; expiresIn: number }> {\r\n const authorizationEndpoint = await this.resolveEndpoint('authorization')\r\n const pushed = await this.pushAuthorizationRequest(options)\r\n\r\n const params = new URLSearchParams({\r\n client_id: this.config.clientId,\r\n request_uri: pushed.requestUri\r\n })\r\n\r\n return {\r\n url: `${authorizationEndpoint}?${params.toString()}`,\r\n codeVerifier: pushed.codeVerifier,\r\n state: pushed.state,\r\n requestUri: pushed.requestUri,\r\n expiresIn: pushed.expiresIn\r\n }\r\n }\r\n\r\n /**\r\n * Create OIDC RP-Initiated Logout URL (`end_session_endpoint`).\r\n */\r\n async createEndSessionUrl(options?: CreateEndSessionUrlOptions): Promise<string> {\r\n const endSessionEndpoint = await this.resolveEndpoint('endSession')\r\n const params = new URLSearchParams()\r\n\r\n if (options?.idTokenHint) {\r\n params.set('id_token_hint', options.idTokenHint)\r\n }\r\n if (options?.postLogoutRedirectUri) {\r\n params.set('post_logout_redirect_uri', options.postLogoutRedirectUri)\r\n }\r\n if (options?.state) {\r\n params.set('state', options.state)\r\n }\r\n\r\n // 帮助服务端在未提供 id_token_hint 时识别客户端\r\n params.set('client_id', options?.clientId ?? this.config.clientId)\r\n\r\n return `${endSessionEndpoint}?${params.toString()}`\r\n }\r\n\r\n // ============================================================\r\n // Token Operations\r\n // ============================================================\r\n\r\n /**\r\n * Exchange an authorization code for tokens (Authorization Code Grant).\r\n */\r\n async exchangeCode(options: ExchangeCodeOptions): Promise<TokenResponse> {\r\n const tokenEndpoint = await this.resolveEndpoint('token')\r\n\r\n try {\r\n const response = await this.httpClient.post(\r\n tokenEndpoint,\r\n {\r\n grant_type: 'authorization_code',\r\n code: options.code,\r\n redirect_uri: options.redirectUri,\r\n code_verifier: options.codeVerifier,\r\n ...this.getClientAuthBody()\r\n },\r\n { headers: this.getClientAuthHeaders() }\r\n )\r\n\r\n return this.mapTokenResponse(response.data)\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n /**\r\n * Refresh an Access Token using a Refresh Token.\r\n */\r\n async refreshToken(refreshToken: string): Promise<TokenResponse> {\r\n const tokenEndpoint = await this.resolveEndpoint('token')\r\n\r\n try {\r\n const response = await this.httpClient.post(\r\n tokenEndpoint,\r\n {\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n ...this.getClientAuthBody()\r\n },\r\n { headers: this.getClientAuthHeaders() }\r\n )\r\n\r\n return this.mapTokenResponse(response.data)\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n /**\r\n * Revoke a token (RFC 7009).\r\n *\r\n * Supports revoking Access Tokens or Refresh Tokens.\r\n * Revoking a Refresh Token also revokes its entire token family.\r\n */\r\n async revokeToken(\r\n token: string,\r\n options?: { tokenTypeHint?: 'access_token' | 'refresh_token' }\r\n ): Promise<void> {\r\n const revocationEndpoint = await this.resolveEndpoint('revocation')\r\n\r\n try {\r\n const tokenTypeHint = options?.tokenTypeHint\r\n ? TokenTypeHintSchema.parse(options.tokenTypeHint)\r\n : undefined\r\n await this.httpClient.post(\r\n revocationEndpoint,\r\n {\r\n token,\r\n token_type_hint: tokenTypeHint,\r\n ...this.getClientAuthBody()\r\n },\r\n { headers: this.getClientAuthHeaders() }\r\n )\r\n } catch {\r\n // RFC 7009: revocation endpoint always returns 200, ignore errors\r\n }\r\n }\r\n\r\n /**\r\n * Token introspection (RFC 7662).\r\n *\r\n * Query the server for the current state of a token (active status, associated user info, etc.).\r\n */\r\n async introspectToken(\r\n token: string,\r\n options?: { tokenTypeHint?: 'access_token' | 'refresh_token' }\r\n ): Promise<IntrospectionResponse> {\r\n const introspectionEndpoint = await this.resolveEndpoint('introspection')\r\n\r\n try {\r\n const tokenTypeHint = options?.tokenTypeHint\r\n ? TokenTypeHintSchema.parse(options.tokenTypeHint)\r\n : undefined\r\n const response = await this.httpClient.post(\r\n introspectionEndpoint,\r\n {\r\n token,\r\n token_type_hint: tokenTypeHint,\r\n ...this.getClientAuthBody()\r\n },\r\n { headers: this.getClientAuthHeaders() }\r\n )\r\n\r\n const raw = IntrospectionResponseSchema.parse(response.data)\r\n return {\r\n active: raw.active,\r\n scope: raw.scope,\r\n clientId: raw.client_id,\r\n username: raw.username,\r\n tokenType: raw.token_type,\r\n exp: raw.exp,\r\n iat: raw.iat,\r\n sub: raw.sub,\r\n aud: raw.aud,\r\n iss: raw.iss,\r\n jti: raw.jti,\r\n sid: raw.sid,\r\n sv: raw.sv\r\n }\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n // ============================================================\r\n // OIDC UserInfo\r\n // ============================================================\r\n\r\n /**\r\n * Get user info using an Access Token (OIDC UserInfo Endpoint).\r\n *\r\n * The returned fields depend on the scopes included in the token:\r\n * - `profile`: name, picture, updatedAt\r\n * - `email`: email, emailVerified\r\n */\r\n async getUserInfo(accessToken: string): Promise<UserInfo> {\r\n const userinfoEndpoint = await this.resolveEndpoint('userinfo')\r\n\r\n try {\r\n const response = await this.httpClient.get(userinfoEndpoint, {\r\n headers: { Authorization: `Bearer ${accessToken}` }\r\n })\r\n\r\n const raw = UserInfoSchema.parse(response.data)\r\n return {\r\n sub: raw.sub,\r\n name: raw.name,\r\n picture: raw.picture,\r\n email: raw.email,\r\n emailVerified: raw.email_verified,\r\n updatedAt: raw.updated_at\r\n }\r\n } catch (error) {\r\n throw this.handleTokenError(error)\r\n }\r\n }\r\n\r\n // ============================================================\r\n // Local JWT Verification\r\n // ============================================================\r\n\r\n /**\r\n * Locally verify a JWT Access Token (RFC 9068).\r\n *\r\n * Uses remote JWKS for signature verification, and validates issuer, audience, expiry, etc.\r\n *\r\n * @param token JWT Access Token string\r\n * @param options.audience Custom audience validation value (defaults to clientId)\r\n */\r\n async verifyAccessToken(\r\n token: string,\r\n options?: { audience?: string }\r\n ): Promise<AccessTokenPayload> {\r\n const verifier = await this.getJwtVerifier()\r\n return verifier.verifyAccessToken(token, options?.audience)\r\n }\r\n\r\n /**\r\n * Locally verify an OIDC ID Token.\r\n *\r\n * @param token JWT ID Token string\r\n * @param options.audience Custom audience validation value (defaults to clientId)\r\n * @param options.nonce Validate the nonce claim (required if nonce was sent during authorization)\r\n */\r\n async verifyIdToken(\r\n token: string,\r\n options?: { audience?: string; nonce?: string }\r\n ): Promise<IdTokenPayload> {\r\n const verifier = await this.getJwtVerifier()\r\n return verifier.verifyIdToken(token, options)\r\n }\r\n\r\n // ============================================================\r\n // Express Middleware\r\n // ============================================================\r\n\r\n /**\r\n * Express middleware: verify the Bearer Token in the request.\r\n *\r\n * After successful verification, use `getAuth(req)` to retrieve the token payload.\r\n *\r\n * @param options.strategy Verification strategy: 'local' (default, JWT local verification) or 'introspection' (remote introspection)\r\n *\r\n * @example\r\n * ```typescript\r\n * import { getAuth } from '@nya-account/node-sdk/express'\r\n *\r\n * app.use('/api', client.authenticate())\r\n *\r\n * app.get('/api/me', (req, res) => {\r\n * const auth = getAuth(req)\r\n * res.json({ userId: auth?.sub })\r\n * })\r\n * ```\r\n */\r\n authenticate(\r\n options?: AuthenticateOptions\r\n ): (req: Request, res: Response, next: NextFunction) => void {\r\n const strategy = options?.strategy ?? 'local'\r\n\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n const token = extractBearerToken(req)\r\n if (!token) {\r\n sendOAuthError(\r\n res,\r\n 401,\r\n 'invalid_token',\r\n 'Missing Bearer token in Authorization header'\r\n )\r\n return\r\n }\r\n\r\n const handleVerification = async (): Promise<void> => {\r\n let payload: AccessTokenPayload\r\n\r\n if (strategy === 'introspection') {\r\n const introspection = await this.introspectToken(token)\r\n if (!introspection.active) {\r\n sendOAuthError(res, 401, 'invalid_token', 'Token is not active')\r\n return\r\n }\r\n const tokenType = introspection.tokenType?.toLowerCase()\r\n if (\r\n tokenType &&\r\n tokenType !== 'bearer' &&\r\n tokenType !== 'access_token'\r\n ) {\r\n sendOAuthError(\r\n res,\r\n 401,\r\n 'invalid_token',\r\n 'Token is not an access token'\r\n )\r\n return\r\n }\r\n payload = {\r\n iss: introspection.iss ?? '',\r\n sub: introspection.sub ?? '',\r\n aud: introspection.aud ?? '',\r\n scope: introspection.scope ?? '',\r\n ver: '1',\r\n iat: introspection.iat ?? 0,\r\n exp: introspection.exp ?? 0,\r\n jti: introspection.jti ?? '',\r\n sid: introspection.sid ?? '',\r\n sv: introspection.sv ?? 0\r\n }\r\n } else {\r\n payload = await this.verifyAccessToken(token)\r\n }\r\n\r\n setAuth(req, payload)\r\n next()\r\n }\r\n\r\n handleVerification().catch(() => {\r\n sendOAuthError(\r\n res,\r\n 401,\r\n 'invalid_token',\r\n 'Invalid or expired access token'\r\n )\r\n })\r\n }\r\n }\r\n\r\n /**\r\n * Express middleware: validate that the token in the request contains the specified scopes.\r\n *\r\n * Must be used after the `authenticate()` middleware.\r\n *\r\n * @example\r\n * ```typescript\r\n * app.get('/api/profile',\r\n * client.authenticate(),\r\n * client.requireScopes('profile'),\r\n * (req, res) => { ... }\r\n * )\r\n * ```\r\n */\r\n requireScopes(\r\n ...scopes: string[]\r\n ): (req: Request, res: Response, next: NextFunction) => void {\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n const auth = getAuth(req)\r\n if (!auth) {\r\n sendOAuthError(res, 401, 'invalid_token', 'Request not authenticated')\r\n return\r\n }\r\n\r\n const tokenScopes = auth.scope.split(' ')\r\n const missingScopes = scopes.filter((s) => !tokenScopes.includes(s))\r\n\r\n if (missingScopes.length > 0) {\r\n sendOAuthError(\r\n res,\r\n 403,\r\n 'insufficient_scope',\r\n `Missing required scopes: ${missingScopes.join(' ')}`\r\n )\r\n return\r\n }\r\n\r\n next()\r\n }\r\n }\r\n\r\n // ============================================================\r\n // Private Methods\r\n // ============================================================\r\n\r\n private async resolveEndpoint(name: EndpointName): Promise<string> {\r\n const explicit = this.config.endpoints?.[name]\r\n if (explicit) {\r\n return explicit\r\n }\r\n\r\n const discovery = await this.discover()\r\n const discoveryKey = DISCOVERY_ENDPOINT_MAP[name]\r\n const endpoint = discovery[discoveryKey]\r\n\r\n if (!endpoint || typeof endpoint !== 'string') {\r\n throw new NyaAccountError(\r\n 'endpoint_not_found',\r\n `Endpoint '${name}' not found in Discovery document`\r\n )\r\n }\r\n\r\n return endpoint\r\n }\r\n\r\n private async getJwtVerifier(): Promise<JwtVerifier> {\r\n if (this.jwtVerifier) {\r\n return this.jwtVerifier\r\n }\r\n\r\n const jwksUri = await this.resolveEndpoint('jwks')\r\n const discovery = await this.discover()\r\n\r\n this.jwtVerifier = new JwtVerifier(\r\n jwksUri,\r\n discovery.issuer,\r\n this.config.clientId\r\n )\r\n return this.jwtVerifier\r\n }\r\n\r\n private mapTokenResponse(data: unknown): TokenResponse {\r\n const raw = TokenResponseSchema.parse(data)\r\n return {\r\n accessToken: raw.access_token,\r\n tokenType: raw.token_type,\r\n expiresIn: raw.expires_in,\r\n refreshToken: raw.refresh_token,\r\n scope: raw.scope,\r\n idToken: raw.id_token\r\n }\r\n }\r\n\r\n private handleTokenError(error: unknown): NyaAccountError {\r\n if (error instanceof NyaAccountError) {\r\n return error\r\n }\r\n\r\n if (error instanceof AxiosError && error.response) {\r\n const parsed = OAuthErrorSchema.safeParse(error.response.data)\r\n if (parsed.success) {\r\n return new OAuthError(\r\n parsed.data.error,\r\n parsed.data.error_description ?? 'Unknown error'\r\n )\r\n }\r\n }\r\n\r\n const message = error instanceof Error ? error.message : 'Unknown error'\r\n return new NyaAccountError('request_failed', `Request failed: ${message}`)\r\n }\r\n}\r\n"],"mappings":";;;;;;;AAEA,MAAa,sBAAsB,EAAE,KAAK,CAAC,gBAAgB,eAAgB,EAAC;AAM5E,MAAa,sBAAsB,EAAE,OAAO;CACxC,cAAc,EAAE,QAAQ;CACxB,YAAY,EAAE,QAAQ;CACtB,YAAY,EAAE,QAAQ;CACtB,eAAe,EAAE,QAAQ;CACzB,OAAO,EAAE,QAAQ;CACjB,UAAU,EAAE,QAAQ,CAAC,UAAU;AAClC,EAAC;AAQF,MAAa,mBAAmB,EAAE,OAAO;CACrC,OAAO,EAAE,QAAQ;CACjB,mBAAmB,EAAE,QAAQ,CAAC,UAAU;AAC3C,EAAC;AAQF,MAAa,8BAA8B,EAAE,OAAO;CAChD,QAAQ,EAAE,SAAS;CACnB,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,WAAW,EAAE,QAAQ,CAAC,UAAU;CAChC,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,IAAI,EAAE,QAAQ,CAAC,UAAU;AAC5B,EAAC;AAQF,MAAa,iBAAiB,EAAE,OAAO;CACnC,KAAK,EAAE,QAAQ;CACf,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,gBAAgB,EAAE,SAAS,CAAC,UAAU;CACtC,YAAY,EAAE,QAAQ,CAAC,UAAU;AACpC,EAAC;AAQF,MAAa,0BAA0B,EAAE,OAAO;CAC5C,QAAQ,EAAE,QAAQ;CAClB,wBAAwB,EAAE,QAAQ;CAClC,gBAAgB,EAAE,QAAQ;CAC1B,mBAAmB,EAAE,QAAQ,CAAC,UAAU;CACxC,UAAU,EAAE,QAAQ;CACpB,qBAAqB,EAAE,QAAQ,CAAC,UAAU;CAC1C,wBAAwB,EAAE,QAAQ,CAAC,UAAU;CAC7C,uCAAuC,EAAE,QAAQ,CAAC,UAAU;CAC5D,sBAAsB,EAAE,QAAQ,CAAC,UAAU;CAC3C,0BAA0B,EAAE,MAAM,EAAE,QAAQ,CAAC;CAC7C,uBAAuB,EAAE,MAAM,EAAE,QAAQ,CAAC;CAC1C,uCAAuC,EAAE,MAAM,EAAE,QAAQ,CAAC;CAC1D,kBAAkB,EAAE,MAAM,EAAE,QAAQ,CAAC;CACrC,yBAAyB,EAAE,MAAM,EAAE,QAAQ,CAAC;CAC5C,uCAAuC,EAAE,MAAM,EAAE,QAAQ,CAAC;CAC1D,kCAAkC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CAChE,kBAAkB,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CAChD,mCAAmC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;CACjE,6BAA6B,EAAE,SAAS,CAAC,UAAU;CACnD,iCAAiC,EAAE,SAAS,CAAC,UAAU;AAC1D,EAAC;AAIF,MAAa,oCAAoC,EAAE,OAAO;CACtD,aAAa,EAAE,QAAQ,CAAC,IAAI,EAAE;CAC9B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,UAAU;AAC1C,EAAC;AAUF,MAAa,2BAA2B,EAAE,OAAO;CAC7C,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,OAAO,EAAE,QAAQ;CACjB,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;CAClC,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAE,EAAC,CAAC,UAAU;AAChD,EAAC;AAQF,MAAa,uBAAuB,EAAE,OAAO;CACzC,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,KAAK,EAAE,QAAQ;CACf,KAAK,EAAE,QAAQ;CACf,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU;CAC5B,gBAAgB,EAAE,SAAS,CAAC,UAAU;CACtC,YAAY,EAAE,QAAQ,CAAC,UAAU;AACpC,EAAC;;;;;;;;;AC1IF,IAAa,kBAAb,cAAqC,MAAM;CAIvC,YAAYA,MAAcC,aAAqB;AAC3C,SAAO,GAAG,KAAK,IAAI,YAAY,EAAE;OAJ5B,YAAA;OACA,mBAAA;AAIL,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,cAAc;CACtB;AACJ;;;;;;AAKD,IAAa,aAAb,cAAgC,gBAAgB;CAC5C,YAAYC,OAAeC,kBAA0B;AACjD,QAAM,OAAO,iBAAiB;AAC9B,OAAK,OAAO;CACf;AACJ;;;;;;AAKD,IAAa,yBAAb,cAA4C,gBAAgB;CACxD,YAAYF,aAAqB;AAC7B,QAAM,6BAA6B,YAAY;AAC/C,OAAK,OAAO;CACf;AACJ;;;;;;AAKD,IAAa,iBAAb,cAAoC,gBAAgB;CAChD,YAAYA,aAAqB;AAC7B,QAAM,mBAAmB,YAAY;AACrC,OAAK,OAAO;CACf;AACJ;;;;;;;;;ACrCD,SAAgB,uBAA+B;AAC3C,QAAO,YAAY,GAAG,CAAC,SAAS,YAAY;AAC/C;;;;;;AAKD,SAAgB,sBAAsBG,cAA8B;AAChE,QAAO,WAAW,SAAS,CAAC,OAAO,aAAa,CAAC,OAAO,YAAY;AACvE;;;;;;AAKD,SAAgB,eAAyB;CACrC,MAAM,eAAe,sBAAsB;CAC3C,MAAM,gBAAgB,sBAAsB,aAAa;AACzD,QAAO;EAAE;EAAc;CAAe;AACzC;;;;;;;;;ACZD,IAAa,cAAb,MAAyB;CAKrB,YAAYC,SAAiBC,QAAgBC,iBAAyB;OAJ9D,YAAA;OACA,cAAA;OACA,uBAAA;AAGJ,OAAK,OAAO,mBAAmB,IAAI,IAAI,SAAS;AAChD,OAAK,SAAS;AACd,OAAK,kBAAkB;CAC1B;;;;;;CAKD,MAAM,kBAAkBC,OAAeC,UAAgD;AACnF,MAAI;GACA,MAAM,EAAE,SAAS,GAAG,MAAM,UAAU,OAAO,KAAK,MAAM;IAClD,YAAY,CAAC,OAAQ;IACrB,QAAQ,KAAK;IACb,UAAU,YAAY,KAAK;GAC9B,EAAC;AACF,UAAO,yBAAyB,MAAM,QAAQ;EACjD,SAAQ,OAAO;AACZ,SAAM,KAAK,UAAU,OAAO,eAAe;EAC9C;CACJ;;;;;;CAKD,MAAM,cAAcD,OAAeE,SAA0E;AACzG,MAAI;GACA,MAAM,EAAE,SAAS,GAAG,MAAM,UAAU,OAAO,KAAK,MAAM;IAClD,YAAY,CAAC,OAAQ;IACrB,QAAQ,KAAK;IACb,UAAU,SAAS,YAAY,KAAK;GACvC,EAAC;GAEF,MAAM,SAAS,qBAAqB,MAAM,QAAQ;AAElD,OAAI,SAAS,oBAAuB,OAAO,UAAU,QAAQ,MACzD,OAAM,IAAI,uBAAuB;AAGrC,UAAO;EACV,SAAQ,OAAO;AACZ,OAAI,iBAAiB,uBACjB,OAAM;AAEV,SAAM,KAAK,UAAU,OAAO,WAAW;EAC1C;CACJ;CAED,UAAkBC,OAAgBC,WAA2C;AACzE,MAAI,iBAAiB,uBACjB,QAAO;AAEX,MAAI,iBAAiB,OAAW,WAC5B,QAAO,IAAI,wBAAwB,EAAE,UAAU;AAEnD,MAAI,iBAAiB,OAAW,yBAC5B,QAAO,IAAI,wBAAwB,EAAE,UAAU,4BAA4B,MAAM,QAAQ;AAE7F,MAAI,iBAAiB,OAAW,+BAC5B,QAAO,IAAI,wBAAwB,EAAE,UAAU;EAEnD,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,SAAO,IAAI,wBAAwB,EAAE,UAAU,wBAAwB,QAAQ;CAClF;AACJ;;;;ACxCD,MAAMC,yBAAwE;CAC1E,eAAe;CACf,4BAA4B;CAC5B,OAAO;CACP,UAAU;CACV,YAAY;CACZ,eAAe;CACf,MAAM;CACN,YAAY;AACf;;AAGD,MAAM,iBAAiB;;AAGvB,MAAM,8BAA8B;AAwCpC,IAAa,mBAAb,MAA8B;CAQ1B,YAAYC,QAA0B;OAP9B,kBAAA;OACA,cAAA;OACA,iBAA2C;OAC3C,0BAA0B;OACjB,yBAAA;OACT,cAAkC;AAGtC,OAAK,SAAS;GACV,GAAG;GACH,QAAQ,OAAO,UAAU;EAC5B;AACD,OAAK,oBAAoB,OAAO,qBAAqB;AACrD,OAAK,aAAa,MAAM,OAAO,EAC3B,SAAS,OAAO,WAAW,IAC9B,EAAC;CACL;;;;;;;;;;CAWD,oBAAoD;AAChD,MAAI,KAAK,OAAO,4BAA4B,sBACxC,QAAO,CAAE;AAEb,SAAO;GACH,WAAW,KAAK,OAAO;GACvB,eAAe,KAAK,OAAO;EAC9B;CACJ;;;;;;;;;;CAOD,uBAAuD;AACnD,MAAI,KAAK,OAAO,4BAA4B,uBAAuB;GAE/D,MAAM,YAAY,mBAAmB,KAAK,OAAO,SAAS;GAC1D,MAAM,gBAAgB,mBAAmB,KAAK,OAAO,aAAa;GAClE,MAAM,cAAc,OAAO,MAAM,EAAE,UAAU,GAAG,cAAc,EAAE,CAAC,SAAS,SAAS;AACnF,UAAO,EAAE,gBAAgB,QAAQ,YAAY,EAAG;EACnD;AACD,SAAO,CAAE;CACZ;;;;;;CASD,MAAM,WAAuC;AACzC,MACI,KAAK,kBACL,KAAK,KAAK,GAAG,KAAK,0BAA0B,KAAK,kBAEjD,QAAO,KAAK;AAGhB,MAAI;GACA,MAAM,OAAO,EAAE,KAAK,OAAO,OAAO;GAClC,MAAM,WAAW,MAAM,KAAK,WAAW,IAAI,IAAI;GAC/C,MAAM,MAAM,wBAAwB,MAAM,SAAS,KAAK;AAExD,QAAK,iBAAiB;IAClB,QAAQ,IAAI;IACZ,uBAAuB,IAAI;IAC3B,eAAe,IAAI;IACnB,kBAAkB,IAAI;IACtB,SAAS,IAAI;IACb,oBAAoB,IAAI;IACxB,uBAAuB,IAAI;IAC3B,oCACI,IAAI;IACR,oBAAoB,IAAI;IACxB,wBAAwB,IAAI;IAC5B,qBAAqB,IAAI;IACzB,kCACI,IAAI;IACR,iBAAiB,IAAI;IACrB,uBAAuB,IAAI;IAC3B,mCACI,IAAI;IACR,+BAA+B,IAAI;IACnC,iBAAiB,IAAI;GACxB;AACD,QAAK,0BAA0B,KAAK,KAAK;AAEzC,UAAO,KAAK;EACf,SAAQ,OAAO;AACZ,OAAI,iBAAiB,eAAgB,OAAM;GAC3C,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,SAAM,IAAI,gBACL,2CAA2C,QAAQ;EAE3D;CACJ;;;;;;CAKD,aAAmB;AACf,OAAK,iBAAiB;AACtB,OAAK,0BAA0B;AAC/B,OAAK,cAAc;CACtB;;;;;;;;;;;;CAYD,MAAM,uBACFC,SAC+B;EAC/B,MAAM,wBAAwB,MAAM,KAAK,gBAAgB,gBAAgB;EAEzE,MAAM,eAAe,sBAAsB;EAC3C,MAAM,gBAAgB,sBAAsB,aAAa;EACzD,MAAM,QAAQ,QAAQ,SAAS,YAAY,GAAG,CAAC,SAAS,YAAY;EAEpE,MAAM,SAAS,IAAI,gBAAgB;GAC/B,WAAW,KAAK,OAAO;GACvB,cAAc,QAAQ;GACtB,eAAe;GACf,OAAO,QAAQ,SAAS;GACxB;GACA,gBAAgB;GAChB,uBAAuB;EAC1B;AAED,MAAI,QAAQ,MACR,QAAO,IAAI,SAAS,QAAQ,MAAM;AAGtC,SAAO;GACH,MAAM,EAAE,sBAAsB,GAAG,OAAO,UAAU,CAAC;GACnD;GACA;EACH;CACJ;;;;;;;;;;CAOD,MAAM,yBACFC,SACuC;EACvC,MAAM,cAAc,MAAM,KAAK,gBAAgB,6BAA6B;EAE5E,MAAM,eAAe,sBAAsB;EAC3C,MAAM,gBAAgB,sBAAsB,aAAa;EACzD,MAAM,QAAQ,QAAQ,SAAS,YAAY,GAAG,CAAC,SAAS,YAAY;EAEpE,MAAMC,UAAkC;GACpC,GAAG,KAAK,mBAAmB;GAC3B,cAAc,QAAQ;GACtB,eAAe;GACf,OAAO,QAAQ,SAAS;GACxB;GACA,gBAAgB;GAChB,uBAAuB;EAC1B;AAED,MAAI,QAAQ,MACR,SAAQ,QAAQ,QAAQ;AAE5B,MAAI,QAAQ,QACR,SAAQ,UAAU,QAAQ;AAG9B,MAAI;GACA,MAAM,WAAW,MAAM,KAAK,WAAW,KAAK,aAAa,SAAS,EAC9D,SAAS,KAAK,sBAAsB,CACvC,EAAC;GACF,MAAM,MAAM,kCAAkC,MAAM,SAAS,KAAK;AAElE,UAAO;IACH,YAAY,IAAI;IAChB,WAAW,IAAI;IACf;IACA;GACH;EACJ,SAAQ,OAAO;AACZ,SAAM,KAAK,iBAAiB,MAAM;EACrC;CACJ;;;;;;CAKD,MAAM,8BACFD,SAC2E;EAC3E,MAAM,wBAAwB,MAAM,KAAK,gBAAgB,gBAAgB;EACzE,MAAM,SAAS,MAAM,KAAK,yBAAyB,QAAQ;EAE3D,MAAM,SAAS,IAAI,gBAAgB;GAC/B,WAAW,KAAK,OAAO;GACvB,aAAa,OAAO;EACvB;AAED,SAAO;GACH,MAAM,EAAE,sBAAsB,GAAG,OAAO,UAAU,CAAC;GACnD,cAAc,OAAO;GACrB,OAAO,OAAO;GACd,YAAY,OAAO;GACnB,WAAW,OAAO;EACrB;CACJ;;;;;;CAKD,MAAM,oBAAoBE,SAAuD;EAC7E,MAAM,qBAAqB,MAAM,KAAK,gBAAgB,aAAa;EACnE,MAAM,SAAS,IAAI;AAEnB,MAAI,SAAS,YACT,QAAO,IAAI,iBAAiB,QAAQ,YAAY;AAEpD,MAAI,SAAS,sBACT,QAAO,IAAI,4BAA4B,QAAQ,sBAAsB;AAEzE,MAAI,SAAS,MACT,QAAO,IAAI,SAAS,QAAQ,MAAM;AAItC,SAAO,IAAI,aAAa,SAAS,YAAY,KAAK,OAAO,SAAS;AAElE,UAAQ,EAAE,mBAAmB,GAAG,OAAO,UAAU,CAAC;CACrD;;;;;;CASD,MAAM,aAAaC,SAAsD;EACrE,MAAM,gBAAgB,MAAM,KAAK,gBAAgB,QAAQ;AAEzD,MAAI;GACA,MAAM,WAAW,MAAM,KAAK,WAAW,KACnC,eACA;IACI,YAAY;IACZ,MAAM,QAAQ;IACd,cAAc,QAAQ;IACtB,eAAe,QAAQ;IACvB,GAAG,KAAK,mBAAmB;GAC9B,GACD,EAAE,SAAS,KAAK,sBAAsB,CAAE,EAC3C;AAED,UAAO,KAAK,iBAAiB,SAAS,KAAK;EAC9C,SAAQ,OAAO;AACZ,SAAM,KAAK,iBAAiB,MAAM;EACrC;CACJ;;;;;;CAKD,MAAM,aAAaC,cAA8C;EAC7D,MAAM,gBAAgB,MAAM,KAAK,gBAAgB,QAAQ;AAEzD,MAAI;GACA,MAAM,WAAW,MAAM,KAAK,WAAW,KACnC,eACA;IACI,YAAY;IACZ,eAAe;IACf,GAAG,KAAK,mBAAmB;GAC9B,GACD,EAAE,SAAS,KAAK,sBAAsB,CAAE,EAC3C;AAED,UAAO,KAAK,iBAAiB,SAAS,KAAK;EAC9C,SAAQ,OAAO;AACZ,SAAM,KAAK,iBAAiB,MAAM;EACrC;CACJ;;;;;;;;;;;;CAQD,MAAM,YACFC,OACAC,SACa;EACb,MAAM,qBAAqB,MAAM,KAAK,gBAAgB,aAAa;AAEnE,MAAI;GACA,MAAM,gBAAgB,SAAS,gBACzB,oBAAoB,MAAM,QAAQ,cAAc;AAEtD,SAAM,KAAK,WAAW,KAClB,oBACA;IACI;IACA,iBAAiB;IACjB,GAAG,KAAK,mBAAmB;GAC9B,GACD,EAAE,SAAS,KAAK,sBAAsB,CAAE,EAC3C;EACJ,QAAO,CAEP;CACJ;;;;;;;;;;CAOD,MAAM,gBACFD,OACAC,SAC8B;EAC9B,MAAM,wBAAwB,MAAM,KAAK,gBAAgB,gBAAgB;AAEzE,MAAI;GACA,MAAM,gBAAgB,SAAS,gBACzB,oBAAoB,MAAM,QAAQ,cAAc;GAEtD,MAAM,WAAW,MAAM,KAAK,WAAW,KACnC,uBACA;IACI;IACA,iBAAiB;IACjB,GAAG,KAAK,mBAAmB;GAC9B,GACD,EAAE,SAAS,KAAK,sBAAsB,CAAE,EAC3C;GAED,MAAM,MAAM,4BAA4B,MAAM,SAAS,KAAK;AAC5D,UAAO;IACH,QAAQ,IAAI;IACZ,OAAO,IAAI;IACX,UAAU,IAAI;IACd,UAAU,IAAI;IACd,WAAW,IAAI;IACf,KAAK,IAAI;IACT,KAAK,IAAI;IACT,KAAK,IAAI;IACT,KAAK,IAAI;IACT,KAAK,IAAI;IACT,KAAK,IAAI;IACT,KAAK,IAAI;IACT,IAAI,IAAI;GACX;EACJ,SAAQ,OAAO;AACZ,SAAM,KAAK,iBAAiB,MAAM;EACrC;CACJ;;;;;;;;;;;;;;CAaD,MAAM,YAAYC,aAAwC;EACtD,MAAM,mBAAmB,MAAM,KAAK,gBAAgB,WAAW;AAE/D,MAAI;GACA,MAAM,WAAW,MAAM,KAAK,WAAW,IAAI,kBAAkB,EACzD,SAAS,EAAE,gBAAgB,SAAS,YAAY,EAAG,EACtD,EAAC;GAEF,MAAM,MAAM,eAAe,MAAM,SAAS,KAAK;AAC/C,UAAO;IACH,KAAK,IAAI;IACT,MAAM,IAAI;IACV,SAAS,IAAI;IACb,OAAO,IAAI;IACX,eAAe,IAAI;IACnB,WAAW,IAAI;GAClB;EACJ,SAAQ,OAAO;AACZ,SAAM,KAAK,iBAAiB,MAAM;EACrC;CACJ;;;;;;;;;;;;;;;;CAcD,MAAM,kBACFF,OACAG,SAC2B;EAC3B,MAAM,WAAW,MAAM,KAAK,gBAAgB;AAC5C,SAAO,SAAS,kBAAkB,OAAO,SAAS,SAAS;CAC9D;;;;;;;;;;;;;;CASD,MAAM,cACFH,OACAI,SACuB;EACvB,MAAM,WAAW,MAAM,KAAK,gBAAgB;AAC5C,SAAO,SAAS,cAAc,OAAO,QAAQ;CAChD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBD,aACIC,SACyD;EACzD,MAAM,WAAW,SAAS,YAAY;AAEtC,SAAO,CAACC,KAAcC,KAAeC,SAAuB;GACxD,MAAM,QAAQ,mBAAmB,IAAI;AACrC,QAAK,OAAO;AACR,mBACI,KACA,KACA,iBACA,+CACH;AACD;GACH;GAED,MAAM,qBAAqB,YAA2B;IAClD,IAAIC;AAEJ,QAAI,aAAa,iBAAiB;KAC9B,MAAM,gBAAgB,MAAM,KAAK,gBAAgB,MAAM;AACvD,UAAK,cAAc,QAAQ;AACvB,qBAAe,KAAK,KAAK,iBAAiB,sBAAsB;AAChE;KACH;KACD,MAAM,YAAY,cAAc,WAAW,aAAa;AACxD,SACI,aACA,cAAc,YACd,cAAc,gBAChB;AACE,qBACI,KACA,KACA,iBACA,+BACH;AACD;KACH;AACD,eAAU;MACN,KAAK,cAAc,OAAO;MAC1B,KAAK,cAAc,OAAO;MAC1B,KAAK,cAAc,OAAO;MAC1B,OAAO,cAAc,SAAS;MAC9B,KAAK;MACL,KAAK,cAAc,OAAO;MAC1B,KAAK,cAAc,OAAO;MAC1B,KAAK,cAAc,OAAO;MAC1B,KAAK,cAAc,OAAO;MAC1B,IAAI,cAAc,MAAM;KAC3B;IACJ,MACG,WAAU,MAAM,KAAK,kBAAkB,MAAM;AAGjD,YAAQ,KAAK,QAAQ;AACrB,UAAM;GACT;AAED,uBAAoB,CAAC,MAAM,MAAM;AAC7B,mBACI,KACA,KACA,iBACA,kCACH;GACJ,EAAC;EACL;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBD,cACI,GAAG,QACsD;AACzD,SAAO,CAACH,KAAcC,KAAeC,SAAuB;GACxD,MAAM,OAAO,QAAQ,IAAI;AACzB,QAAK,MAAM;AACP,mBAAe,KAAK,KAAK,iBAAiB,4BAA4B;AACtE;GACH;GAED,MAAM,cAAc,KAAK,MAAM,MAAM,IAAI;GACzC,MAAM,gBAAgB,OAAO,OAAO,CAAC,OAAO,YAAY,SAAS,EAAE,CAAC;AAEpE,OAAI,cAAc,SAAS,GAAG;AAC1B,mBACI,KACA,KACA,uBACC,2BAA2B,cAAc,KAAK,IAAI,CAAC,EACvD;AACD;GACH;AAED,SAAM;EACT;CACJ;CAMD,MAAc,gBAAgBE,MAAqC;EAC/D,MAAM,WAAW,KAAK,OAAO,YAAY;AACzC,MAAI,SACA,QAAO;EAGX,MAAM,YAAY,MAAM,KAAK,UAAU;EACvC,MAAM,eAAe,uBAAuB;EAC5C,MAAM,WAAW,UAAU;AAE3B,OAAK,mBAAmB,aAAa,SACjC,OAAM,IAAI,gBACN,uBACC,YAAY,KAAK;AAI1B,SAAO;CACV;CAED,MAAc,iBAAuC;AACjD,MAAI,KAAK,YACL,QAAO,KAAK;EAGhB,MAAM,UAAU,MAAM,KAAK,gBAAgB,OAAO;EAClD,MAAM,YAAY,MAAM,KAAK,UAAU;AAEvC,OAAK,cAAc,IAAI,YACnB,SACA,UAAU,QACV,KAAK,OAAO;AAEhB,SAAO,KAAK;CACf;CAED,iBAAyBC,MAA8B;EACnD,MAAM,MAAM,oBAAoB,MAAM,KAAK;AAC3C,SAAO;GACH,aAAa,IAAI;GACjB,WAAW,IAAI;GACf,WAAW,IAAI;GACf,cAAc,IAAI;GAClB,OAAO,IAAI;GACX,SAAS,IAAI;EAChB;CACJ;CAED,iBAAyBC,OAAiC;AACtD,MAAI,iBAAiB,gBACjB,QAAO;AAGX,MAAI,iBAAiB,cAAc,MAAM,UAAU;GAC/C,MAAM,SAAS,iBAAiB,UAAU,MAAM,SAAS,KAAK;AAC9D,OAAI,OAAO,QACP,QAAO,IAAI,WACP,OAAO,KAAK,OACZ,OAAO,KAAK,qBAAqB;EAG5C;EAED,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,SAAO,IAAI,gBAAgB,mBAAmB,kBAAkB,QAAQ;CAC3E;AACJ"}
package/package.json CHANGED
@@ -1,79 +1,78 @@
1
1
  {
2
- "name": "@nya-account/node-sdk",
3
- "version": "2.0.1",
4
- "description": "Official Node.js SDK for Nya Account SSO — OAuth 2.1 / OIDC client with PKCE, JWT verification, and Express middleware",
5
- "license": "MIT",
6
- "author": {
7
- "name": "Neko Along"
2
+ "name": "@nya-account/node-sdk",
3
+ "version": "2.0.3",
4
+ "description": "Official Node.js SDK for Nya Account SSO — OAuth 2.1 / OIDC client with PKCE, JWT verification, and Express middleware",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "Neko Along"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/alongw/sso.git",
12
+ "directory": "packages/node-sdk"
13
+ },
14
+ "homepage": "https://github.com/alongw/sso/tree/main/packages/node-sdk#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/alongw/sso/issues"
17
+ },
18
+ "keywords": [
19
+ "sso",
20
+ "oauth",
21
+ "oauth2",
22
+ "oidc",
23
+ "openid-connect",
24
+ "pkce",
25
+ "jwt",
26
+ "nya-account",
27
+ "authentication",
28
+ "authorization",
29
+ "express-middleware"
30
+ ],
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "type": "module",
34
+ "exports": {
35
+ ".": {
36
+ "import": "./dist/index.js",
37
+ "types": "./dist/index.d.ts"
8
38
  },
9
- "repository": {
10
- "type": "git",
11
- "url": "https://github.com/alongw/sso.git",
12
- "directory": "packages/node-sdk"
13
- },
14
- "homepage": "https://github.com/alongw/sso/tree/main/packages/node-sdk#readme",
15
- "bugs": {
16
- "url": "https://github.com/alongw/sso/issues"
17
- },
18
- "keywords": [
19
- "sso",
20
- "oauth",
21
- "oauth2",
22
- "oidc",
23
- "openid-connect",
24
- "pkce",
25
- "jwt",
26
- "nya-account",
27
- "authentication",
28
- "authorization",
29
- "express-middleware"
30
- ],
31
- "main": "./dist/index.js",
32
- "types": "./dist/index.d.ts",
33
- "type": "module",
34
- "exports": {
35
- ".": {
36
- "import": "./dist/index.js",
37
- "types": "./dist/index.d.ts"
38
- },
39
- "./express": {
40
- "import": "./dist/express.js",
41
- "types": "./dist/express.d.ts"
42
- }
43
- },
44
- "files": [
45
- "dist",
46
- "README.md",
47
- "LICENSE"
48
- ],
49
- "scripts": {
50
- "build": "tsdown",
51
- "dev": "tsdown --watch",
52
- "type-check": "tsc --noEmit",
53
- "prepublishOnly": "pnpm run build"
54
- },
55
- "engines": {
56
- "node": ">=20.0.0"
57
- },
58
- "publishConfig": {
59
- "access": "public"
60
- },
61
- "dependencies": {
62
- "axios": "^1.7.9",
63
- "jose": "^6.1.3",
64
- "zod": "^3.24.1"
65
- },
66
- "devDependencies": {
67
- "@types/express": "^5.0.6",
68
- "@types/node": "^22.15.21",
69
- "tsdown": "^0.9.4"
70
- },
71
- "peerDependencies": {
72
- "express": "^4.0.0 || ^5.0.0"
73
- },
74
- "peerDependenciesMeta": {
75
- "express": {
76
- "optional": true
77
- }
39
+ "./express": {
40
+ "import": "./dist/express.js",
41
+ "types": "./dist/express.d.ts"
42
+ }
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "README.md",
47
+ "LICENSE"
48
+ ],
49
+ "engines": {
50
+ "node": ">=20.0.0"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "dependencies": {
56
+ "axios": "^1.7.9",
57
+ "jose": "^6.1.3",
58
+ "zod": "^3.24.1"
59
+ },
60
+ "devDependencies": {
61
+ "@types/express": "^5.0.6",
62
+ "@types/node": "^22.15.21",
63
+ "tsdown": "^0.9.4"
64
+ },
65
+ "peerDependencies": {
66
+ "express": "^4.0.0 || ^5.0.0"
67
+ },
68
+ "peerDependenciesMeta": {
69
+ "express": {
70
+ "optional": true
78
71
  }
72
+ },
73
+ "scripts": {
74
+ "build": "tsdown",
75
+ "dev": "tsdown --watch",
76
+ "type-check": "tsc --noEmit"
77
+ }
79
78
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"express-yO7hxKKd.d.ts","names":[],"sources":["../src/core/schemas.d.ts","../src/middleware/express.d.ts"],"sourcesContent":null,"mappings":";;;;AAWA,IAAW,2BAAW;CAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;AAAA;AACtB,IAAW,qBAAc;CAAA;CAAA,MAAA;CAAA,MAAA,EAAA;AAAA;AACzB,IAAW,uBAAM;CAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;CAAA,MAAA,EAAA;AAAA;AACjB,IAAW,iBAAiB;CAAC;CAAI,MAAA;CAAA,MAAA,EAAA;AAAA;;;;;;;;;;;;;;;;;;;ACGjC,IAAW,UAAU,CAAC,GAAG,MAAM,kBAAmB;;;;AAQlD,IAAW,qBAAqB,CAAC,GAAG,MAAM,OAAQ;;;;AAIlD,IAAW,iBAAiB,CAAC,GAAG,MAAM,QAAS"}