win-portal-auth-sdk 1.0.0 → 1.1.0
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 +146 -1
- package/TYPE_SAFETY.md +97 -0
- package/dist/client/api/auth.api.d.ts +58 -4
- package/dist/client/api/auth.api.d.ts.map +1 -1
- package/dist/client/api/auth.api.js +64 -2
- package/dist/client/api/files.api.d.ts +5 -5
- package/dist/client/api/files.api.d.ts.map +1 -1
- package/dist/client/api/index.d.ts +5 -0
- package/dist/client/api/index.d.ts.map +1 -1
- package/dist/client/api/index.js +8 -1
- package/dist/client/api/line.api.d.ts +150 -0
- package/dist/client/api/line.api.d.ts.map +1 -0
- package/dist/client/api/line.api.js +114 -0
- package/dist/client/api/oauth.api.d.ts +221 -0
- package/dist/client/api/oauth.api.d.ts.map +1 -0
- package/dist/client/api/oauth.api.js +258 -0
- package/dist/client/api/system-config.api.d.ts +4 -14
- package/dist/client/api/system-config.api.d.ts.map +1 -1
- package/dist/client/api/system-config.api.js +0 -8
- package/dist/client/auth-client.d.ts +16 -1
- package/dist/client/auth-client.d.ts.map +1 -1
- package/dist/client/auth-client.js +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/middleware/express.middleware.d.ts +62 -0
- package/dist/middleware/express.middleware.d.ts.map +1 -0
- package/dist/middleware/express.middleware.js +185 -0
- package/dist/middleware/express.types.d.ts +28 -0
- package/dist/middleware/express.types.d.ts.map +1 -0
- package/dist/middleware/express.types.js +7 -0
- package/dist/middleware/index.d.ts +8 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +26 -0
- package/dist/middleware/nestjs.decorators.d.ts +31 -0
- package/dist/middleware/nestjs.decorators.d.ts.map +1 -0
- package/dist/middleware/nestjs.decorators.js +56 -0
- package/dist/middleware/nestjs.guard.d.ts +55 -0
- package/dist/middleware/nestjs.guard.d.ts.map +1 -0
- package/dist/middleware/nestjs.guard.js +188 -0
- package/dist/middleware/types.d.ts +59 -0
- package/dist/middleware/types.d.ts.map +1 -0
- package/dist/middleware/types.js +5 -0
- package/dist/types/auth.types.d.ts +16 -13
- package/dist/types/auth.types.d.ts.map +1 -1
- package/dist/types/auth.types.js +2 -2
- package/dist/types/file.types.d.ts +13 -9
- package/dist/types/file.types.d.ts.map +1 -1
- package/dist/types/file.types.js +2 -2
- package/dist/types/system-config.types.d.ts +8 -18
- package/dist/types/system-config.types.d.ts.map +1 -1
- package/dist/types/system-config.types.js +2 -2
- package/package.json +8 -2
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OAuth 2.0 & OpenID Connect API
|
|
4
|
+
*
|
|
5
|
+
* Client methods for OAuth 2.0 Authorization Code Flow with PKCE
|
|
6
|
+
* and OpenID Connect authentication
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.generateState = exports.generatePKCE = exports.OAuthAPI = void 0;
|
|
10
|
+
class OAuthAPI {
|
|
11
|
+
constructor(client, config) {
|
|
12
|
+
this.client = client;
|
|
13
|
+
this.config = config;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate authorization URL for OAuth 2.0 Authorization Code Flow
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const pkce = generatePKCE(); // Helper function (implement separately)
|
|
21
|
+
* const authUrl = oauth.getAuthorizationUrl({
|
|
22
|
+
* state: 'random_state_string',
|
|
23
|
+
* codeChallenge: pkce.codeChallenge,
|
|
24
|
+
* codeChallengeMethod: 'S256',
|
|
25
|
+
* scope: 'openid profile email'
|
|
26
|
+
* });
|
|
27
|
+
* // Redirect user to authUrl
|
|
28
|
+
* window.location.href = authUrl;
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
getAuthorizationUrl(options = {}) {
|
|
32
|
+
const baseUrl = this.client['client'].defaults.baseURL;
|
|
33
|
+
const params = new URLSearchParams({
|
|
34
|
+
client_id: this.config.clientId,
|
|
35
|
+
redirect_uri: this.config.redirectUri,
|
|
36
|
+
response_type: options.responseType || 'code',
|
|
37
|
+
scope: options.scope || this.config.scope || 'openid profile email',
|
|
38
|
+
});
|
|
39
|
+
if (options.state) {
|
|
40
|
+
params.append('state', options.state);
|
|
41
|
+
}
|
|
42
|
+
if (options.codeChallenge) {
|
|
43
|
+
params.append('code_challenge', options.codeChallenge);
|
|
44
|
+
params.append('code_challenge_method', options.codeChallengeMethod || 'S256');
|
|
45
|
+
}
|
|
46
|
+
return `${baseUrl}/oauth/authorize?${params.toString()}`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Exchange authorization code for access token
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* // After user is redirected back with code
|
|
54
|
+
* const urlParams = new URLSearchParams(window.location.search);
|
|
55
|
+
* const code = urlParams.get('code');
|
|
56
|
+
*
|
|
57
|
+
* const tokens = await oauth.exchangeCodeForToken(code, {
|
|
58
|
+
* codeVerifier: pkce.codeVerifier // From PKCE generation
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* console.log('Access Token:', tokens.access_token);
|
|
62
|
+
* console.log('ID Token:', tokens.id_token);
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
async exchangeCodeForToken(code, options = {}) {
|
|
66
|
+
const data = {
|
|
67
|
+
grant_type: 'authorization_code',
|
|
68
|
+
code,
|
|
69
|
+
redirect_uri: this.config.redirectUri,
|
|
70
|
+
client_id: this.config.clientId,
|
|
71
|
+
};
|
|
72
|
+
// Add client_secret for confidential clients
|
|
73
|
+
if (this.config.clientSecret) {
|
|
74
|
+
data.client_secret = this.config.clientSecret;
|
|
75
|
+
}
|
|
76
|
+
// Add PKCE code_verifier if provided
|
|
77
|
+
if (options.codeVerifier) {
|
|
78
|
+
data.code_verifier = options.codeVerifier;
|
|
79
|
+
}
|
|
80
|
+
const response = await this.client.post('/oauth/token', data);
|
|
81
|
+
return response.data;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Refresh access token using refresh token
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const newTokens = await oauth.refreshAccessToken(refreshToken);
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
async refreshAccessToken(refreshToken) {
|
|
92
|
+
const data = {
|
|
93
|
+
grant_type: 'refresh_token',
|
|
94
|
+
refresh_token: refreshToken,
|
|
95
|
+
client_id: this.config.clientId,
|
|
96
|
+
};
|
|
97
|
+
if (this.config.clientSecret) {
|
|
98
|
+
data.client_secret = this.config.clientSecret;
|
|
99
|
+
}
|
|
100
|
+
const response = await this.client.post('/oauth/token', data);
|
|
101
|
+
return response.data;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get user information from UserInfo endpoint (OIDC)
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```typescript
|
|
108
|
+
* const userInfo = await oauth.getUserInfo(accessToken);
|
|
109
|
+
* console.log('User:', userInfo.name, userInfo.email);
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
async getUserInfo(accessToken) {
|
|
113
|
+
const response = await this.client.get('/oauth/userinfo', {
|
|
114
|
+
headers: {
|
|
115
|
+
Authorization: `Bearer ${accessToken}`,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
return response.data;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Revoke access or refresh token
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* await oauth.revokeToken(accessToken, 'access_token');
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
async revokeToken(token, tokenTypeHint) {
|
|
129
|
+
const data = {
|
|
130
|
+
token,
|
|
131
|
+
client_id: this.config.clientId,
|
|
132
|
+
};
|
|
133
|
+
if (tokenTypeHint) {
|
|
134
|
+
data.token_type_hint = tokenTypeHint;
|
|
135
|
+
}
|
|
136
|
+
if (this.config.clientSecret) {
|
|
137
|
+
data.client_secret = this.config.clientSecret;
|
|
138
|
+
}
|
|
139
|
+
await this.client.post('/oauth/revoke', data);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Introspect token to check if it's valid
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const result = await oauth.introspectToken(accessToken);
|
|
147
|
+
* if (result.active) {
|
|
148
|
+
* console.log('Token is valid, expires at:', result.exp);
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
async introspectToken(token) {
|
|
153
|
+
const data = {
|
|
154
|
+
token,
|
|
155
|
+
client_id: this.config.clientId,
|
|
156
|
+
};
|
|
157
|
+
if (this.config.clientSecret) {
|
|
158
|
+
data.client_secret = this.config.clientSecret;
|
|
159
|
+
}
|
|
160
|
+
const response = await this.client.post('/oauth/introspect', data);
|
|
161
|
+
return response.data;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get OpenID Connect Discovery Document
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* const discovery = await oauth.getDiscoveryDocument();
|
|
169
|
+
* console.log('Issuer:', discovery.issuer);
|
|
170
|
+
* console.log('Authorization Endpoint:', discovery.authorization_endpoint);
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
async getDiscoveryDocument() {
|
|
174
|
+
const response = await this.client.get('/.well-known/openid-configuration');
|
|
175
|
+
return response.data;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get JSON Web Key Set (JWKS) for token verification
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* const jwks = await oauth.getJWKS();
|
|
183
|
+
* // Use jwks to verify ID tokens
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
async getJWKS() {
|
|
187
|
+
const response = await this.client.get('/oauth/jwks');
|
|
188
|
+
return response.data;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.OAuthAPI = OAuthAPI;
|
|
192
|
+
/**
|
|
193
|
+
* PKCE Helper Functions
|
|
194
|
+
*/
|
|
195
|
+
/**
|
|
196
|
+
* Generate random string for state/verifier
|
|
197
|
+
*/
|
|
198
|
+
function generateRandomString(length) {
|
|
199
|
+
const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
|
|
200
|
+
const randomValues = new Uint8Array(length);
|
|
201
|
+
crypto.getRandomValues(randomValues);
|
|
202
|
+
return Array.from(randomValues)
|
|
203
|
+
.map((v) => charset[v % charset.length])
|
|
204
|
+
.join('');
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Generate SHA-256 hash
|
|
208
|
+
*/
|
|
209
|
+
async function sha256(plain) {
|
|
210
|
+
const encoder = new TextEncoder();
|
|
211
|
+
const data = encoder.encode(plain);
|
|
212
|
+
return crypto.subtle.digest('SHA-256', data);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Base64 URL encode
|
|
216
|
+
*/
|
|
217
|
+
function base64UrlEncode(buffer) {
|
|
218
|
+
const bytes = new Uint8Array(buffer);
|
|
219
|
+
let binary = '';
|
|
220
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
221
|
+
binary += String.fromCharCode(bytes[i]);
|
|
222
|
+
}
|
|
223
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Generate PKCE code verifier and challenge
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```typescript
|
|
230
|
+
* const pkce = await generatePKCE();
|
|
231
|
+
* // Store pkce.codeVerifier in sessionStorage
|
|
232
|
+
* // Use pkce.codeChallenge in authorization URL
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
async function generatePKCE() {
|
|
236
|
+
const codeVerifier = generateRandomString(128);
|
|
237
|
+
const hashed = await sha256(codeVerifier);
|
|
238
|
+
const codeChallenge = base64UrlEncode(hashed);
|
|
239
|
+
return {
|
|
240
|
+
codeVerifier,
|
|
241
|
+
codeChallenge,
|
|
242
|
+
codeChallengeMethod: 'S256',
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
exports.generatePKCE = generatePKCE;
|
|
246
|
+
/**
|
|
247
|
+
* Generate random state parameter
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* const state = generateState();
|
|
252
|
+
* // Store in sessionStorage for CSRF protection
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
function generateState() {
|
|
256
|
+
return generateRandomString(32);
|
|
257
|
+
}
|
|
258
|
+
exports.generateState = generateState;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AuthClient } from '../auth-client';
|
|
2
|
-
import {
|
|
2
|
+
import { SystemConfig, SystemConfigByCategory } from '../../types';
|
|
3
3
|
/**
|
|
4
4
|
* System Config API
|
|
5
5
|
* Methods for retrieving system configurations
|
|
@@ -8,30 +8,20 @@ import { SystemConfigResponseDto, SystemConfigSearchParams, SystemConfigCategory
|
|
|
8
8
|
export declare class SystemConfigAPI {
|
|
9
9
|
private client;
|
|
10
10
|
constructor(client: AuthClient);
|
|
11
|
-
/**
|
|
12
|
-
* GET /system-configs
|
|
13
|
-
* ดึงรายการ system configs (with pagination)
|
|
14
|
-
*/
|
|
15
|
-
search(params?: SystemConfigSearchParams): Promise<{
|
|
16
|
-
data: SystemConfigResponseDto[];
|
|
17
|
-
total: number;
|
|
18
|
-
page: number;
|
|
19
|
-
page_size: number;
|
|
20
|
-
}>;
|
|
21
11
|
/**
|
|
22
12
|
* GET /system-configs/categories/:category
|
|
23
13
|
* ดึง configs ตาม category - ส่ง object ที่รวมทุก key เป็น { key1: value1, key2: value2 }
|
|
24
14
|
*/
|
|
25
|
-
getByCategory(category: string): Promise<
|
|
15
|
+
getByCategory(category: string): Promise<SystemConfigByCategory>;
|
|
26
16
|
/**
|
|
27
17
|
* GET /system-configs/categories/:category/:key
|
|
28
18
|
* ดึง config ตาม category และ key - ส่ง full metadata row
|
|
29
19
|
*/
|
|
30
|
-
getByCategoryAndKey(category: string, key: string): Promise<
|
|
20
|
+
getByCategoryAndKey(category: string, key: string): Promise<SystemConfig>;
|
|
31
21
|
/**
|
|
32
22
|
* GET /system-configs/categories/security
|
|
33
23
|
* ดึง security configs ทั้งหมด (convenience method)
|
|
34
24
|
*/
|
|
35
|
-
security(): Promise<
|
|
25
|
+
security(): Promise<SystemConfigByCategory>;
|
|
36
26
|
}
|
|
37
27
|
//# sourceMappingURL=system-config.api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-config.api.d.ts","sourceRoot":"","sources":["../../../src/client/api/system-config.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"system-config.api.d.ts","sourceRoot":"","sources":["../../../src/client/api/system-config.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAEnE;;;;GAIG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,UAAU;IAEtC;;;OAGG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAKtE;;;OAGG;IACG,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAK/E;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,sBAAsB,CAAC;CAGlD"}
|
|
@@ -10,14 +10,6 @@ class SystemConfigAPI {
|
|
|
10
10
|
constructor(client) {
|
|
11
11
|
this.client = client;
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
14
|
-
* GET /system-configs
|
|
15
|
-
* ดึงรายการ system configs (with pagination)
|
|
16
|
-
*/
|
|
17
|
-
async search(params) {
|
|
18
|
-
const response = await this.client.get('/system-configs', { params });
|
|
19
|
-
return response.data;
|
|
20
|
-
}
|
|
21
13
|
/**
|
|
22
14
|
* GET /system-configs/categories/:category
|
|
23
15
|
* ดึง configs ตาม category - ส่ง object ที่รวมทุก key เป็น { key1: value1, key2: value2 }
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
9
9
|
import { AuthSdkConfig } from '../types';
|
|
10
|
-
import { AuthAPI, HealthAPI, SystemConfigAPI, FilesAPI, EventLogApi } from './api';
|
|
10
|
+
import { AuthAPI, HealthAPI, SystemConfigAPI, FilesAPI, EventLogApi, OAuthAPI, OAuthConfig, LineAPI } from './api';
|
|
11
11
|
export declare class AuthClient {
|
|
12
12
|
private client;
|
|
13
13
|
private apiKey;
|
|
@@ -18,7 +18,22 @@ export declare class AuthClient {
|
|
|
18
18
|
readonly systemConfig: SystemConfigAPI;
|
|
19
19
|
readonly files: FilesAPI;
|
|
20
20
|
readonly eventLog: EventLogApi;
|
|
21
|
+
readonly line: LineAPI;
|
|
22
|
+
oauth?: OAuthAPI;
|
|
21
23
|
constructor(config: AuthSdkConfig);
|
|
24
|
+
/**
|
|
25
|
+
* Initialize OAuth client for OAuth 2.0 flows
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* authClient.initializeOAuth({
|
|
30
|
+
* clientId: 'your-client-id',
|
|
31
|
+
* redirectUri: 'https://yourapp.com/callback',
|
|
32
|
+
* scope: 'openid profile email'
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
initializeOAuth(config: OAuthConfig): void;
|
|
22
37
|
/**
|
|
23
38
|
* GET request
|
|
24
39
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../../src/client/auth-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../../src/client/auth-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAc,EAAE,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEnH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,KAAK,CAAuB;IAGpC,SAAgB,IAAI,EAAE,OAAO,CAAC;IAC9B,SAAgB,MAAM,EAAE,SAAS,CAAC;IAClC,SAAgB,YAAY,EAAE,eAAe,CAAC;IAC9C,SAAgB,KAAK,EAAE,QAAQ,CAAC;IAChC,SAAgB,QAAQ,EAAE,WAAW,CAAC;IACtC,SAAgB,IAAI,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,QAAQ,CAAC;gBAEZ,MAAM,EAAE,aAAa;IAoDjC;;;;;;;;;;;OAWG;IACH,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAI1C;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAIvF;;OAEG;IACG,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAIpG;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAInG;;OAEG;IACG,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAIrG;;OAEG;IACG,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI1F;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,eAAe,IAAI,MAAM;IAMzB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B;;OAEG;IACH,cAAc,IAAI,MAAM;IAOxB;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,gBAAgB,IAAI,aAAa;CAGlC"}
|
|
@@ -54,6 +54,22 @@ class AuthClient {
|
|
|
54
54
|
this.systemConfig = new api_1.SystemConfigAPI(this);
|
|
55
55
|
this.files = new api_1.FilesAPI(this);
|
|
56
56
|
this.eventLog = new api_1.EventLogApi(this);
|
|
57
|
+
this.line = new api_1.LineAPI(this);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Initialize OAuth client for OAuth 2.0 flows
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* authClient.initializeOAuth({
|
|
65
|
+
* clientId: 'your-client-id',
|
|
66
|
+
* redirectUri: 'https://yourapp.com/callback',
|
|
67
|
+
* scope: 'openid profile email'
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
initializeOAuth(config) {
|
|
72
|
+
this.oauth = new api_1.OAuthAPI(this, config);
|
|
57
73
|
}
|
|
58
74
|
/**
|
|
59
75
|
* GET request
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC;AAGzB,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -24,3 +24,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
24
24
|
__exportStar(require("./types"), exports);
|
|
25
25
|
// Client (Frontend & Backend)
|
|
26
26
|
__exportStar(require("./client"), exports);
|
|
27
|
+
// Middleware (Backend only - Express & NestJS)
|
|
28
|
+
__exportStar(require("./middleware"), exports);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express Middleware for Win Portal Auth
|
|
3
|
+
*
|
|
4
|
+
* Simple middleware that injects user profile into req.user
|
|
5
|
+
*/
|
|
6
|
+
import { User } from '../types';
|
|
7
|
+
import { MiddlewareConfig, AuthContext } from './types';
|
|
8
|
+
import './express.types';
|
|
9
|
+
/**
|
|
10
|
+
* Create Express/NestJS middleware
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { authMiddleware } from 'win-portal-auth-sdk';
|
|
15
|
+
*
|
|
16
|
+
* // Express
|
|
17
|
+
* app.use(authMiddleware({
|
|
18
|
+
* baseURL: 'https://api.example.com',
|
|
19
|
+
* apiKey: 'your-api-key'
|
|
20
|
+
* }));
|
|
21
|
+
*
|
|
22
|
+
* // In routes
|
|
23
|
+
* app.get('/profile', (req, res) => {
|
|
24
|
+
* const user = req.user; // User
|
|
25
|
+
* const token = req.token;
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function authMiddleware(config: MiddlewareConfig): (req: any, res: any, next: any) => Promise<any>;
|
|
30
|
+
/**
|
|
31
|
+
* Get Auth from Request
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const { user, token } = getAuth(req);
|
|
36
|
+
* if (user) {
|
|
37
|
+
* console.log(user.email, user.permissions);
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAuth(req: any): AuthContext;
|
|
42
|
+
/**
|
|
43
|
+
* Require Auth - throws if not authenticated
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* app.get('/protected', (req, res) => {
|
|
48
|
+
* const { user } = requireAuth(req);
|
|
49
|
+
* // user is guaranteed to be non-null
|
|
50
|
+
* res.json({ email: user.email });
|
|
51
|
+
* });
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function requireAuth(req: any): {
|
|
55
|
+
user: User;
|
|
56
|
+
token: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Clear user cache (useful for testing or manual cache invalidation)
|
|
60
|
+
*/
|
|
61
|
+
export declare function clearAuthCache(token?: string): void;
|
|
62
|
+
//# sourceMappingURL=express.middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/express.middleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGxD,OAAO,iBAAiB,CAAC;AAUzB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,SAYlC,GAAG,OAAO,GAAG,QAAQ,GAAG,kBAoG5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,WAAW,CAK7C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG;IACrC,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf,CASA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,QAM5C"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Express Middleware for Win Portal Auth
|
|
4
|
+
*
|
|
5
|
+
* Simple middleware that injects user profile into req.user
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.clearAuthCache = exports.requireAuth = exports.getAuth = exports.authMiddleware = void 0;
|
|
9
|
+
const client_1 = require("../client");
|
|
10
|
+
// Import Express type augmentation
|
|
11
|
+
require("./express.types");
|
|
12
|
+
const userCache = new Map();
|
|
13
|
+
/**
|
|
14
|
+
* Create Express/NestJS middleware
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { authMiddleware } from 'win-portal-auth-sdk';
|
|
19
|
+
*
|
|
20
|
+
* // Express
|
|
21
|
+
* app.use(authMiddleware({
|
|
22
|
+
* baseURL: 'https://api.example.com',
|
|
23
|
+
* apiKey: 'your-api-key'
|
|
24
|
+
* }));
|
|
25
|
+
*
|
|
26
|
+
* // In routes
|
|
27
|
+
* app.get('/profile', (req, res) => {
|
|
28
|
+
* const user = req.user; // User
|
|
29
|
+
* const token = req.token;
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function authMiddleware(config) {
|
|
34
|
+
const client = new client_1.AuthClient({
|
|
35
|
+
baseURL: config.baseURL,
|
|
36
|
+
apiKey: config.apiKey,
|
|
37
|
+
apiKeyHeader: config.apiKeyHeader,
|
|
38
|
+
});
|
|
39
|
+
const cacheTimeout = (config.cacheTimeout || 300) * 1000; // Convert to ms
|
|
40
|
+
const tokenStrategy = config.tokenStrategy || 'bearer';
|
|
41
|
+
const cookieName = config.cookieName || 'access_token';
|
|
42
|
+
const excludePaths = config.excludePaths || [];
|
|
43
|
+
return async (req, res, next) => {
|
|
44
|
+
// No type assertion needed - req already has user/token from Express.Request augmentation
|
|
45
|
+
// Check if path is excluded
|
|
46
|
+
const shouldSkip = excludePaths.some((pattern) => {
|
|
47
|
+
if (typeof pattern === 'string') {
|
|
48
|
+
return req.path === pattern;
|
|
49
|
+
}
|
|
50
|
+
return pattern.test(req.path);
|
|
51
|
+
});
|
|
52
|
+
if (shouldSkip) {
|
|
53
|
+
req.user = null;
|
|
54
|
+
req.token = null;
|
|
55
|
+
return next();
|
|
56
|
+
}
|
|
57
|
+
// Extract token
|
|
58
|
+
let token = null;
|
|
59
|
+
if (config.tokenExtractor) {
|
|
60
|
+
token = config.tokenExtractor(req);
|
|
61
|
+
}
|
|
62
|
+
else if (tokenStrategy === 'bearer') {
|
|
63
|
+
const authHeader = req.headers.authorization;
|
|
64
|
+
if (authHeader && authHeader.startsWith('Bearer ')) {
|
|
65
|
+
token = authHeader.substring(7);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (tokenStrategy === 'cookie') {
|
|
69
|
+
token = req.cookies?.[cookieName] || null;
|
|
70
|
+
}
|
|
71
|
+
// No token found
|
|
72
|
+
if (!token) {
|
|
73
|
+
if (config.optional) {
|
|
74
|
+
req.user = null;
|
|
75
|
+
req.token = null;
|
|
76
|
+
return next();
|
|
77
|
+
}
|
|
78
|
+
return res.status(401).json({
|
|
79
|
+
statusCode: 401,
|
|
80
|
+
message: 'Authentication required',
|
|
81
|
+
error: 'Unauthorized',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
// Check cache first
|
|
86
|
+
const cached = userCache.get(token);
|
|
87
|
+
if (cached && Date.now() - cached.timestamp < cacheTimeout) {
|
|
88
|
+
req.user = cached.user;
|
|
89
|
+
req.token = token;
|
|
90
|
+
return next();
|
|
91
|
+
}
|
|
92
|
+
// Fetch user profile from API
|
|
93
|
+
client.setToken(token);
|
|
94
|
+
const user = await client.auth.profile();
|
|
95
|
+
// Update cache
|
|
96
|
+
userCache.set(token, {
|
|
97
|
+
user,
|
|
98
|
+
timestamp: Date.now(),
|
|
99
|
+
});
|
|
100
|
+
// Clean up old cache entries (simple cleanup)
|
|
101
|
+
if (userCache.size > 1000) {
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
const entries = Array.from(userCache.entries());
|
|
104
|
+
for (const [key, entry] of entries) {
|
|
105
|
+
if (now - entry.timestamp > cacheTimeout) {
|
|
106
|
+
userCache.delete(key);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Attach user to request
|
|
111
|
+
req.user = user;
|
|
112
|
+
req.token = token;
|
|
113
|
+
next();
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
// Clear cache on error
|
|
117
|
+
userCache.delete(token);
|
|
118
|
+
if (config.optional) {
|
|
119
|
+
req.user = null;
|
|
120
|
+
req.token = null;
|
|
121
|
+
return next();
|
|
122
|
+
}
|
|
123
|
+
const status = error.response?.status || 401;
|
|
124
|
+
const message = error.response?.data?.message || 'Authentication failed';
|
|
125
|
+
return res.status(status).json({
|
|
126
|
+
statusCode: status,
|
|
127
|
+
message,
|
|
128
|
+
error: 'Unauthorized',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
exports.authMiddleware = authMiddleware;
|
|
134
|
+
/**
|
|
135
|
+
* Get Auth from Request
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const { user, token } = getAuth(req);
|
|
140
|
+
* if (user) {
|
|
141
|
+
* console.log(user.email, user.permissions);
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
function getAuth(req) {
|
|
146
|
+
return {
|
|
147
|
+
user: req.user || null,
|
|
148
|
+
token: req.token || null,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
exports.getAuth = getAuth;
|
|
152
|
+
/**
|
|
153
|
+
* Require Auth - throws if not authenticated
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* app.get('/protected', (req, res) => {
|
|
158
|
+
* const { user } = requireAuth(req);
|
|
159
|
+
* // user is guaranteed to be non-null
|
|
160
|
+
* res.json({ email: user.email });
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
function requireAuth(req) {
|
|
165
|
+
if (!req.user || !req.token) {
|
|
166
|
+
throw new Error('Authentication required');
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
user: req.user,
|
|
170
|
+
token: req.token,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
exports.requireAuth = requireAuth;
|
|
174
|
+
/**
|
|
175
|
+
* Clear user cache (useful for testing or manual cache invalidation)
|
|
176
|
+
*/
|
|
177
|
+
function clearAuthCache(token) {
|
|
178
|
+
if (token) {
|
|
179
|
+
userCache.delete(token);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
userCache.clear();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
exports.clearAuthCache = clearAuthCache;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express Type Extensions
|
|
3
|
+
*
|
|
4
|
+
* Extends Express Request interface to include auth properties
|
|
5
|
+
*/
|
|
6
|
+
import { User } from '../types';
|
|
7
|
+
declare global {
|
|
8
|
+
namespace Express {
|
|
9
|
+
interface Request {
|
|
10
|
+
/**
|
|
11
|
+
* Authenticated user profile
|
|
12
|
+
* - Set by authMiddleware when token is valid
|
|
13
|
+
* - null when optional=true and no token provided
|
|
14
|
+
* - undefined when middleware not applied to route
|
|
15
|
+
*/
|
|
16
|
+
user?: User | null;
|
|
17
|
+
/**
|
|
18
|
+
* Access token used for authentication
|
|
19
|
+
* - Extracted from Authorization header or cookie
|
|
20
|
+
* - null when optional=true and no token provided
|
|
21
|
+
* - undefined when middleware not applied to route
|
|
22
|
+
*/
|
|
23
|
+
token?: string | null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=express.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.types.d.ts","sourceRoot":"","sources":["../../src/middleware/express.types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf;;;;;eAKG;YACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;YAEnB;;;;;eAKG;YACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;SACvB;KACF;CACF;AAGD,OAAO,EAAE,CAAC"}
|