@theranova/auth-sdk 0.1.0 → 0.3.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 +18 -3
- package/package.json +1 -1
- package/src/core/TheranovaAuth.d.ts +54 -5
- package/src/core/TheranovaAuth.d.ts.map +1 -1
- package/src/core/TheranovaAuth.js +77 -3
- package/src/core/TheranovaAuth.js.map +1 -1
- package/src/core/device-info.d.ts +80 -0
- package/src/core/device-info.d.ts.map +1 -0
- package/src/core/device-info.js +171 -0
- package/src/core/device-info.js.map +1 -0
- package/src/core/logout.d.ts +2 -2
- package/src/core/logout.d.ts.map +1 -1
- package/src/core/logout.js +11 -9
- package/src/core/logout.js.map +1 -1
- package/src/index.d.ts +10 -3
- package/src/index.d.ts.map +1 -1
- package/src/index.js +10 -3
- package/src/index.js.map +1 -1
package/README.md
CHANGED
|
@@ -17,8 +17,8 @@ pnpm add @theranova/auth-sdk
|
|
|
17
17
|
```typescript
|
|
18
18
|
import { TheranovaAuth } from '@theranova/auth-sdk';
|
|
19
19
|
|
|
20
|
+
// 프로덕션 환경 - issuer 생략 (기본값 사용)
|
|
20
21
|
const auth = new TheranovaAuth({
|
|
21
|
-
issuer: 'https://auth.theranova.com',
|
|
22
22
|
clientId: 'your-client-id',
|
|
23
23
|
redirectUri: 'https://your-app.com/callback',
|
|
24
24
|
});
|
|
@@ -31,12 +31,15 @@ await auth.login();
|
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
33
|
interface TheranovaAuthConfig {
|
|
34
|
-
/** Authorization server issuer URL */
|
|
35
|
-
issuer: string;
|
|
36
34
|
/** OAuth2 client ID */
|
|
37
35
|
clientId: string;
|
|
38
36
|
/** Redirect URI for OAuth2 callback */
|
|
39
37
|
redirectUri: string;
|
|
38
|
+
/**
|
|
39
|
+
* Authorization server issuer URL (optional)
|
|
40
|
+
* @default 'https://auth.theranova.co.kr'
|
|
41
|
+
*/
|
|
42
|
+
issuer?: string;
|
|
40
43
|
/** OAuth2 scopes (default: openid profile email offline_access) */
|
|
41
44
|
scopes?: string[];
|
|
42
45
|
/** Storage key for tokens (default: theranova_auth_tokens) */
|
|
@@ -46,6 +49,18 @@ interface TheranovaAuthConfig {
|
|
|
46
49
|
}
|
|
47
50
|
```
|
|
48
51
|
|
|
52
|
+
### 개발 환경 설정
|
|
53
|
+
|
|
54
|
+
로컬 개발 시에만 `issuer`를 override:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const auth = new TheranovaAuth({
|
|
58
|
+
clientId: 'your-client-id',
|
|
59
|
+
redirectUri: 'http://localhost:4200/callback',
|
|
60
|
+
issuer: 'http://localhost:3001', // 로컬 Auth 서버
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
49
64
|
## Usage
|
|
50
65
|
|
|
51
66
|
### Login
|
package/package.json
CHANGED
|
@@ -3,19 +3,45 @@
|
|
|
3
3
|
* Main class for OAuth2 PKCE authentication
|
|
4
4
|
*/
|
|
5
5
|
import { type TokenStorage } from './token-manager';
|
|
6
|
+
import { type DeviceInfo } from './device-info';
|
|
6
7
|
export interface TheranovaAuthConfig {
|
|
7
|
-
/** Authorization server issuer URL (e.g., https://auth.theranova.com) */
|
|
8
|
-
issuer: string;
|
|
9
8
|
/** OAuth2 client ID */
|
|
10
9
|
clientId: string;
|
|
11
10
|
/** Redirect URI for OAuth2 callback */
|
|
12
11
|
redirectUri: string;
|
|
12
|
+
/**
|
|
13
|
+
* Authorization server issuer URL (optional)
|
|
14
|
+
* @default 'https://auth.theranova.co.kr'
|
|
15
|
+
* @description 개발 환경에서만 override 필요 (예: 'http://localhost:3001')
|
|
16
|
+
*/
|
|
17
|
+
issuer?: string;
|
|
13
18
|
/** OAuth2 scopes (default: openid profile email offline_access) */
|
|
14
19
|
scopes?: string[];
|
|
15
20
|
/** Storage key for tokens (default: theranova_auth_tokens) */
|
|
16
21
|
storageKey?: string;
|
|
17
22
|
/** Post-logout redirect URI */
|
|
18
23
|
postLogoutRedirectUri?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Automatically register device after login callback
|
|
26
|
+
* @default true
|
|
27
|
+
* @description 로그인 완료 후 자동으로 기기 등록 API 호출
|
|
28
|
+
*/
|
|
29
|
+
autoRegisterDevice?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** Device registration request payload */
|
|
32
|
+
export interface DeviceRegistrationPayload {
|
|
33
|
+
deviceType: DeviceInfo['deviceType'];
|
|
34
|
+
platform: string;
|
|
35
|
+
platformVersion?: string;
|
|
36
|
+
browser: string;
|
|
37
|
+
browserVersion?: string;
|
|
38
|
+
model?: string;
|
|
39
|
+
mobile: boolean;
|
|
40
|
+
architecture?: string;
|
|
41
|
+
bitness?: string;
|
|
42
|
+
userAgent: string;
|
|
43
|
+
uaHintSupported: boolean;
|
|
44
|
+
deviceName: string;
|
|
19
45
|
}
|
|
20
46
|
export interface TheranovaAuthTokens {
|
|
21
47
|
accessToken: string;
|
|
@@ -28,18 +54,41 @@ export declare class TheranovaAuth {
|
|
|
28
54
|
private config;
|
|
29
55
|
private tokenManager;
|
|
30
56
|
constructor(config: TheranovaAuthConfig);
|
|
57
|
+
/**
|
|
58
|
+
* Get the configured issuer URL
|
|
59
|
+
*/
|
|
60
|
+
getIssuer(): string;
|
|
31
61
|
/**
|
|
32
62
|
* Start OAuth2 PKCE login flow
|
|
33
63
|
* Generates PKCE challenge and redirects to authorization server
|
|
64
|
+
*
|
|
65
|
+
* @param options.prompt - OAuth2 prompt parameter ('login' | 'consent' | 'select_account' | 'none')
|
|
66
|
+
* 'login': 항상 로그인 화면 표시 (히스토리 있으면 계정 선택)
|
|
34
67
|
*/
|
|
35
|
-
login(
|
|
68
|
+
login(options?: {
|
|
69
|
+
prompt?: string;
|
|
70
|
+
}): Promise<void>;
|
|
36
71
|
/**
|
|
37
72
|
* Handle OAuth2 callback
|
|
38
|
-
* Exchanges authorization code for tokens
|
|
73
|
+
* Exchanges authorization code for tokens and optionally registers device
|
|
39
74
|
*
|
|
75
|
+
* @param options.skipDeviceRegistration - Skip automatic device registration
|
|
40
76
|
* @returns The tokens if successful, null if there was an error
|
|
41
77
|
*/
|
|
42
|
-
handleCallback(
|
|
78
|
+
handleCallback(options?: {
|
|
79
|
+
skipDeviceRegistration?: boolean;
|
|
80
|
+
}): Promise<TheranovaAuthTokens | null>;
|
|
81
|
+
/**
|
|
82
|
+
* Register current device with the auth server
|
|
83
|
+
* Uses UA Hints API for accurate device information when available
|
|
84
|
+
*
|
|
85
|
+
* @returns Device info that was sent to the server
|
|
86
|
+
*/
|
|
87
|
+
registerDevice(): Promise<DeviceInfo>;
|
|
88
|
+
/**
|
|
89
|
+
* Get current device info (without registering)
|
|
90
|
+
*/
|
|
91
|
+
getDeviceInfo(): Promise<DeviceInfo>;
|
|
43
92
|
/**
|
|
44
93
|
* Exchange authorization code for tokens
|
|
45
94
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TheranovaAuth.d.ts","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/TheranovaAuth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"TheranovaAuth.d.ts","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/TheranovaAuth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,MAAM,WAAW,mBAAmB;IAClC,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,0CAA0C;AAC1C,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAUD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAA8G;IAC5H,OAAO,CAAC,YAAY,CAAe;gBAEvB,MAAM,EAAE,mBAAmB;IAUvC;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;;;;;OAMG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiCzD;;;;;;OAMG;IACG,cAAc,CAAC,OAAO,CAAC,EAAE;QAAE,sBAAsB,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IA0DzG;;;;;OAKG;IACG,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC;IA6C3C;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAI1C;;OAEG;YACW,qBAAqB;IAiCnC;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAoD/D;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY9C;;OAEG;IACH,SAAS,IAAI,YAAY,GAAG,IAAI;IAIhC;;OAEG;IACH,eAAe,IAAI,OAAO;IAI1B;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;;OAGG;IACH,kBAAkB,IAAI,MAAM,GAAG,IAAI;IASnC;;OAEG;IACH,YAAY,IAAI,IAAI;IASpB;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAkB7C;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAM5B;;OAEG;YACW,qBAAqB;IAOnC;;OAEG;IACH,OAAO,CAAC,eAAe;CAUxB"}
|
|
@@ -4,19 +4,33 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { TokenManager } from './token-manager';
|
|
6
6
|
import { logout as localLogout, logoutGlobal, logoutAndRedirect } from './logout';
|
|
7
|
+
import { getDeviceInfo, getDeviceDisplayName } from './device-info';
|
|
8
|
+
/** Default Theranova Auth Server URL */
|
|
9
|
+
const DEFAULT_ISSUER = 'https://auth.theranova.co.kr';
|
|
7
10
|
export class TheranovaAuth {
|
|
8
11
|
constructor(config) {
|
|
9
12
|
this.config = {
|
|
10
13
|
...config,
|
|
14
|
+
issuer: config.issuer || DEFAULT_ISSUER,
|
|
11
15
|
scopes: config.scopes || ['openid', 'profile', 'email', 'offline_access'],
|
|
16
|
+
autoRegisterDevice: config.autoRegisterDevice ?? true,
|
|
12
17
|
};
|
|
13
18
|
this.tokenManager = new TokenManager(config.storageKey);
|
|
14
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the configured issuer URL
|
|
22
|
+
*/
|
|
23
|
+
getIssuer() {
|
|
24
|
+
return this.config.issuer;
|
|
25
|
+
}
|
|
15
26
|
/**
|
|
16
27
|
* Start OAuth2 PKCE login flow
|
|
17
28
|
* Generates PKCE challenge and redirects to authorization server
|
|
29
|
+
*
|
|
30
|
+
* @param options.prompt - OAuth2 prompt parameter ('login' | 'consent' | 'select_account' | 'none')
|
|
31
|
+
* 'login': 항상 로그인 화면 표시 (히스토리 있으면 계정 선택)
|
|
18
32
|
*/
|
|
19
|
-
async login() {
|
|
33
|
+
async login(options) {
|
|
20
34
|
// Generate state for CSRF protection
|
|
21
35
|
const state = this.generateRandomString(32);
|
|
22
36
|
// Generate PKCE code verifier and challenge
|
|
@@ -34,6 +48,8 @@ export class TheranovaAuth {
|
|
|
34
48
|
authUrl.searchParams.set('redirect_uri', this.config.redirectUri);
|
|
35
49
|
authUrl.searchParams.set('scope', this.config.scopes.join(' '));
|
|
36
50
|
authUrl.searchParams.set('state', state);
|
|
51
|
+
// prompt 파라미터: 기본값 'login' (계정 선택/로그인 화면 표시)
|
|
52
|
+
authUrl.searchParams.set('prompt', options?.prompt || 'login');
|
|
37
53
|
authUrl.searchParams.set('code_challenge', codeChallenge);
|
|
38
54
|
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
39
55
|
// Redirect to authorization server
|
|
@@ -43,11 +59,12 @@ export class TheranovaAuth {
|
|
|
43
59
|
}
|
|
44
60
|
/**
|
|
45
61
|
* Handle OAuth2 callback
|
|
46
|
-
* Exchanges authorization code for tokens
|
|
62
|
+
* Exchanges authorization code for tokens and optionally registers device
|
|
47
63
|
*
|
|
64
|
+
* @param options.skipDeviceRegistration - Skip automatic device registration
|
|
48
65
|
* @returns The tokens if successful, null if there was an error
|
|
49
66
|
*/
|
|
50
|
-
async handleCallback() {
|
|
67
|
+
async handleCallback(options) {
|
|
51
68
|
if (typeof window === 'undefined') {
|
|
52
69
|
return null;
|
|
53
70
|
}
|
|
@@ -86,8 +103,63 @@ export class TheranovaAuth {
|
|
|
86
103
|
// Clean up sessionStorage
|
|
87
104
|
sessionStorage.removeItem('oauth2_state');
|
|
88
105
|
sessionStorage.removeItem('oauth2_code_verifier');
|
|
106
|
+
// Auto-register device (non-blocking)
|
|
107
|
+
if (this.config.autoRegisterDevice && !options?.skipDeviceRegistration) {
|
|
108
|
+
this.registerDevice().catch((err) => {
|
|
109
|
+
console.warn('[TheranovaAuth] Device registration failed (non-critical):', err);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
89
112
|
return tokens;
|
|
90
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Register current device with the auth server
|
|
116
|
+
* Uses UA Hints API for accurate device information when available
|
|
117
|
+
*
|
|
118
|
+
* @returns Device info that was sent to the server
|
|
119
|
+
*/
|
|
120
|
+
async registerDevice() {
|
|
121
|
+
const accessToken = this.tokenManager.getAccessToken();
|
|
122
|
+
if (!accessToken) {
|
|
123
|
+
throw new Error('Not authenticated. Please login first.');
|
|
124
|
+
}
|
|
125
|
+
// Collect device info using UA Hints
|
|
126
|
+
const deviceInfo = await getDeviceInfo();
|
|
127
|
+
const deviceName = getDeviceDisplayName(deviceInfo);
|
|
128
|
+
const payload = {
|
|
129
|
+
deviceType: deviceInfo.deviceType,
|
|
130
|
+
platform: deviceInfo.platform,
|
|
131
|
+
platformVersion: deviceInfo.platformVersion,
|
|
132
|
+
browser: deviceInfo.browser,
|
|
133
|
+
browserVersion: deviceInfo.browserVersion,
|
|
134
|
+
model: deviceInfo.model,
|
|
135
|
+
mobile: deviceInfo.mobile,
|
|
136
|
+
architecture: deviceInfo.architecture,
|
|
137
|
+
bitness: deviceInfo.bitness,
|
|
138
|
+
userAgent: deviceInfo.userAgent,
|
|
139
|
+
uaHintSupported: deviceInfo.uaHintSupported,
|
|
140
|
+
deviceName,
|
|
141
|
+
};
|
|
142
|
+
const response = await fetch(`${this.config.issuer}/device/register`, {
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: {
|
|
145
|
+
'Content-Type': 'application/json',
|
|
146
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
147
|
+
},
|
|
148
|
+
body: JSON.stringify(payload),
|
|
149
|
+
});
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const errorData = await response.json().catch(() => ({}));
|
|
152
|
+
throw new Error(errorData.message || `Device registration failed: ${response.status}`);
|
|
153
|
+
}
|
|
154
|
+
console.log('[TheranovaAuth] Device registered:', deviceName, deviceInfo.uaHintSupported ? '(UA Hints)' : '(User-Agent fallback)');
|
|
155
|
+
return deviceInfo;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get current device info (without registering)
|
|
159
|
+
*/
|
|
160
|
+
async getDeviceInfo() {
|
|
161
|
+
return getDeviceInfo();
|
|
162
|
+
}
|
|
91
163
|
/**
|
|
92
164
|
* Exchange authorization code for tokens
|
|
93
165
|
*/
|
|
@@ -206,6 +278,7 @@ export class TheranovaAuth {
|
|
|
206
278
|
return logoutGlobal({
|
|
207
279
|
tokenManager: this.tokenManager,
|
|
208
280
|
issuer: this.config.issuer,
|
|
281
|
+
clientId: this.config.clientId,
|
|
209
282
|
postLogoutRedirectUri: this.config.postLogoutRedirectUri || this.config.redirectUri,
|
|
210
283
|
});
|
|
211
284
|
}
|
|
@@ -216,6 +289,7 @@ export class TheranovaAuth {
|
|
|
216
289
|
logoutAndRedirect({
|
|
217
290
|
tokenManager: this.tokenManager,
|
|
218
291
|
issuer: this.config.issuer,
|
|
292
|
+
clientId: this.config.clientId,
|
|
219
293
|
postLogoutRedirectUri: this.config.postLogoutRedirectUri || this.config.redirectUri,
|
|
220
294
|
});
|
|
221
295
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TheranovaAuth.js","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/TheranovaAuth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAqB,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,MAAM,IAAI,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"TheranovaAuth.js","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/TheranovaAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device Info - UA Hint 기반 기기 정보 수집
|
|
3
|
+
*
|
|
4
|
+
* User-Agent Client Hints API를 사용하여 더 정확한 기기 정보를 수집합니다.
|
|
5
|
+
* 지원하지 않는 브라우저에서는 기존 User-Agent 파싱으로 폴백합니다.
|
|
6
|
+
*/
|
|
7
|
+
export interface DeviceInfo {
|
|
8
|
+
/** 기기 유형 */
|
|
9
|
+
deviceType: 'DESKTOP' | 'MOBILE' | 'WEB' | 'TABLET' | 'OTHER';
|
|
10
|
+
/** 플랫폼 (Windows, macOS, Android, iOS, Linux) */
|
|
11
|
+
platform: string;
|
|
12
|
+
/** 플랫폼 버전 */
|
|
13
|
+
platformVersion?: string;
|
|
14
|
+
/** 브라우저 이름 */
|
|
15
|
+
browser: string;
|
|
16
|
+
/** 브라우저 버전 */
|
|
17
|
+
browserVersion?: string;
|
|
18
|
+
/** 기기 모델 (모바일) */
|
|
19
|
+
model?: string;
|
|
20
|
+
/** 모바일 여부 */
|
|
21
|
+
mobile: boolean;
|
|
22
|
+
/** 아키텍처 (x86, arm) */
|
|
23
|
+
architecture?: string;
|
|
24
|
+
/** 비트 수 (32, 64) */
|
|
25
|
+
bitness?: string;
|
|
26
|
+
/** 원본 User-Agent 문자열 */
|
|
27
|
+
userAgent: string;
|
|
28
|
+
/** UA Hint 사용 여부 */
|
|
29
|
+
uaHintSupported: boolean;
|
|
30
|
+
}
|
|
31
|
+
interface NavigatorUAData {
|
|
32
|
+
brands: {
|
|
33
|
+
brand: string;
|
|
34
|
+
version: string;
|
|
35
|
+
}[];
|
|
36
|
+
mobile: boolean;
|
|
37
|
+
platform: string;
|
|
38
|
+
getHighEntropyValues(hints: string[]): Promise<{
|
|
39
|
+
platform?: string;
|
|
40
|
+
platformVersion?: string;
|
|
41
|
+
architecture?: string;
|
|
42
|
+
model?: string;
|
|
43
|
+
bitness?: string;
|
|
44
|
+
mobile?: boolean;
|
|
45
|
+
uaFullVersion?: string;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
declare global {
|
|
49
|
+
interface Navigator {
|
|
50
|
+
userAgentData?: NavigatorUAData;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 기기 정보 수집 (UA Hint 우선, 폴백으로 User-Agent 파싱)
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const deviceInfo = await getDeviceInfo();
|
|
59
|
+
* console.log(deviceInfo);
|
|
60
|
+
* // {
|
|
61
|
+
* // deviceType: 'DESKTOP',
|
|
62
|
+
* // platform: 'Windows',
|
|
63
|
+
* // platformVersion: '10.0.0',
|
|
64
|
+
* // browser: 'Chrome',
|
|
65
|
+
* // browserVersion: '120',
|
|
66
|
+
* // mobile: false,
|
|
67
|
+
* // architecture: 'x86',
|
|
68
|
+
* // bitness: '64',
|
|
69
|
+
* // userAgent: '...',
|
|
70
|
+
* // uaHintSupported: true
|
|
71
|
+
* // }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function getDeviceInfo(): Promise<DeviceInfo>;
|
|
75
|
+
/**
|
|
76
|
+
* 기기 정보를 사람이 읽기 쉬운 이름으로 변환
|
|
77
|
+
*/
|
|
78
|
+
export declare function getDeviceDisplayName(info: DeviceInfo): string;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=device-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-info.d.ts","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/device-info.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,UAAU;IACzB,YAAY;IACZ,UAAU,EAAE,SAAS,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC9D,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,sBAAsB;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAGD,UAAU,eAAe;IACvB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7C,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC,CAAC;CACJ;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,SAAS;QACjB,aAAa,CAAC,EAAE,eAAe,CAAC;KACjC;CACF;AAwHD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAsBzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAM7D"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device Info - UA Hint 기반 기기 정보 수집
|
|
3
|
+
*
|
|
4
|
+
* User-Agent Client Hints API를 사용하여 더 정확한 기기 정보를 수집합니다.
|
|
5
|
+
* 지원하지 않는 브라우저에서는 기존 User-Agent 파싱으로 폴백합니다.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* User-Agent 문자열에서 기기 정보 파싱 (폴백)
|
|
9
|
+
*/
|
|
10
|
+
function parseUserAgent(ua) {
|
|
11
|
+
const uaLower = ua.toLowerCase();
|
|
12
|
+
// 기기 유형 판별
|
|
13
|
+
let deviceType = 'DESKTOP';
|
|
14
|
+
let mobile = false;
|
|
15
|
+
if (uaLower.includes('mobile') || uaLower.includes('android') || uaLower.includes('iphone')) {
|
|
16
|
+
deviceType = 'MOBILE';
|
|
17
|
+
mobile = true;
|
|
18
|
+
}
|
|
19
|
+
else if (uaLower.includes('tablet') || uaLower.includes('ipad')) {
|
|
20
|
+
deviceType = 'TABLET';
|
|
21
|
+
mobile = true;
|
|
22
|
+
}
|
|
23
|
+
// 플랫폼 판별
|
|
24
|
+
let platform = 'Unknown';
|
|
25
|
+
if (uaLower.includes('windows'))
|
|
26
|
+
platform = 'Windows';
|
|
27
|
+
else if (uaLower.includes('mac os') || uaLower.includes('macos'))
|
|
28
|
+
platform = 'macOS';
|
|
29
|
+
else if (uaLower.includes('android'))
|
|
30
|
+
platform = 'Android';
|
|
31
|
+
else if (uaLower.includes('iphone') || uaLower.includes('ipad') || uaLower.includes('ios'))
|
|
32
|
+
platform = 'iOS';
|
|
33
|
+
else if (uaLower.includes('linux'))
|
|
34
|
+
platform = 'Linux';
|
|
35
|
+
else if (uaLower.includes('cros'))
|
|
36
|
+
platform = 'Chrome OS';
|
|
37
|
+
// 브라우저 판별
|
|
38
|
+
let browser = 'Unknown';
|
|
39
|
+
let browserVersion;
|
|
40
|
+
if (uaLower.includes('edg/')) {
|
|
41
|
+
browser = 'Edge';
|
|
42
|
+
browserVersion = ua.match(/Edg\/(\d+(\.\d+)?)/)?.[1];
|
|
43
|
+
}
|
|
44
|
+
else if (uaLower.includes('chrome') && !uaLower.includes('chromium')) {
|
|
45
|
+
browser = 'Chrome';
|
|
46
|
+
browserVersion = ua.match(/Chrome\/(\d+(\.\d+)?)/)?.[1];
|
|
47
|
+
}
|
|
48
|
+
else if (uaLower.includes('firefox')) {
|
|
49
|
+
browser = 'Firefox';
|
|
50
|
+
browserVersion = ua.match(/Firefox\/(\d+(\.\d+)?)/)?.[1];
|
|
51
|
+
}
|
|
52
|
+
else if (uaLower.includes('safari') && !uaLower.includes('chrome')) {
|
|
53
|
+
browser = 'Safari';
|
|
54
|
+
browserVersion = ua.match(/Version\/(\d+(\.\d+)?)/)?.[1];
|
|
55
|
+
}
|
|
56
|
+
else if (uaLower.includes('opera') || uaLower.includes('opr/')) {
|
|
57
|
+
browser = 'Opera';
|
|
58
|
+
browserVersion = ua.match(/(?:Opera|OPR)\/(\d+(\.\d+)?)/)?.[1];
|
|
59
|
+
}
|
|
60
|
+
// 모델 추출 (괄호 안의 정보)
|
|
61
|
+
const modelMatch = ua.match(/\(([^)]+)\)/);
|
|
62
|
+
const model = modelMatch?.[1];
|
|
63
|
+
return {
|
|
64
|
+
deviceType,
|
|
65
|
+
platform,
|
|
66
|
+
browser,
|
|
67
|
+
browserVersion,
|
|
68
|
+
mobile,
|
|
69
|
+
model,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* UA Hint API를 사용하여 기기 정보 수집
|
|
74
|
+
*/
|
|
75
|
+
async function getDeviceInfoFromUAHint() {
|
|
76
|
+
if (!navigator.userAgentData) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const highEntropyData = await navigator.userAgentData.getHighEntropyValues([
|
|
81
|
+
'platform',
|
|
82
|
+
'platformVersion',
|
|
83
|
+
'architecture',
|
|
84
|
+
'model',
|
|
85
|
+
'bitness',
|
|
86
|
+
'mobile',
|
|
87
|
+
]);
|
|
88
|
+
const brands = navigator.userAgentData.brands;
|
|
89
|
+
const mobile = navigator.userAgentData.mobile;
|
|
90
|
+
// 메인 브라우저 브랜드 찾기 (Chromium 제외)
|
|
91
|
+
const mainBrand = brands.find(b => !b.brand.includes('Chromium') &&
|
|
92
|
+
!b.brand.includes('Not')) || brands[0];
|
|
93
|
+
// 기기 유형 판별
|
|
94
|
+
let deviceType = 'DESKTOP';
|
|
95
|
+
if (mobile) {
|
|
96
|
+
// 태블릿과 모바일 구분 (화면 크기 기반)
|
|
97
|
+
if (typeof window !== 'undefined' && window.screen) {
|
|
98
|
+
const minDimension = Math.min(window.screen.width, window.screen.height);
|
|
99
|
+
deviceType = minDimension >= 600 ? 'TABLET' : 'MOBILE';
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
deviceType = 'MOBILE';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
deviceType,
|
|
107
|
+
platform: highEntropyData.platform || navigator.userAgentData.platform,
|
|
108
|
+
platformVersion: highEntropyData.platformVersion,
|
|
109
|
+
browser: mainBrand?.brand || 'Unknown',
|
|
110
|
+
browserVersion: mainBrand?.version,
|
|
111
|
+
model: highEntropyData.model || undefined,
|
|
112
|
+
mobile,
|
|
113
|
+
architecture: highEntropyData.architecture,
|
|
114
|
+
bitness: highEntropyData.bitness,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
console.warn('[TheranovaAuth] UA Hint API error, falling back to User-Agent parsing:', error);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 기기 정보 수집 (UA Hint 우선, 폴백으로 User-Agent 파싱)
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const deviceInfo = await getDeviceInfo();
|
|
128
|
+
* console.log(deviceInfo);
|
|
129
|
+
* // {
|
|
130
|
+
* // deviceType: 'DESKTOP',
|
|
131
|
+
* // platform: 'Windows',
|
|
132
|
+
* // platformVersion: '10.0.0',
|
|
133
|
+
* // browser: 'Chrome',
|
|
134
|
+
* // browserVersion: '120',
|
|
135
|
+
* // mobile: false,
|
|
136
|
+
* // architecture: 'x86',
|
|
137
|
+
* // bitness: '64',
|
|
138
|
+
* // userAgent: '...',
|
|
139
|
+
* // uaHintSupported: true
|
|
140
|
+
* // }
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export async function getDeviceInfo() {
|
|
144
|
+
const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : '';
|
|
145
|
+
// UA Hint API 시도
|
|
146
|
+
const uaHintInfo = await getDeviceInfoFromUAHint();
|
|
147
|
+
if (uaHintInfo) {
|
|
148
|
+
return {
|
|
149
|
+
...uaHintInfo,
|
|
150
|
+
userAgent,
|
|
151
|
+
uaHintSupported: true,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// 폴백: User-Agent 문자열 파싱
|
|
155
|
+
const parsedInfo = parseUserAgent(userAgent);
|
|
156
|
+
return {
|
|
157
|
+
...parsedInfo,
|
|
158
|
+
userAgent,
|
|
159
|
+
uaHintSupported: false,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 기기 정보를 사람이 읽기 쉬운 이름으로 변환
|
|
164
|
+
*/
|
|
165
|
+
export function getDeviceDisplayName(info) {
|
|
166
|
+
const browserPart = info.browserVersion
|
|
167
|
+
? `${info.browser} ${info.browserVersion.split('.')[0]}`
|
|
168
|
+
: info.browser;
|
|
169
|
+
return `${browserPart} on ${info.platform}`;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=device-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-info.js","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/device-info.ts"],"names":[],"mappings":"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"}
|
package/src/core/logout.d.ts
CHANGED
|
@@ -10,10 +10,10 @@ export interface LogoutOptions {
|
|
|
10
10
|
storageKey?: string;
|
|
11
11
|
/** Authorization server issuer URL */
|
|
12
12
|
issuer?: string;
|
|
13
|
+
/** OAuth2 Client ID */
|
|
14
|
+
clientId?: string;
|
|
13
15
|
/** Post-logout redirect URI */
|
|
14
16
|
postLogoutRedirectUri?: string;
|
|
15
|
-
/** ID token for global logout */
|
|
16
|
-
idToken?: string;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Local logout
|
package/src/core/logout.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/logout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/logout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,IAAI,CASxD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAwBlE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAY9D"}
|
package/src/core/logout.js
CHANGED
|
@@ -24,21 +24,16 @@ export function logout(options = {}) {
|
|
|
24
24
|
* @returns The logout URL to redirect to, or null if issuer is not provided
|
|
25
25
|
*/
|
|
26
26
|
export function logoutGlobal(options) {
|
|
27
|
-
const { issuer,
|
|
27
|
+
const { issuer, clientId, postLogoutRedirectUri, tokenManager, storageKey } = options;
|
|
28
28
|
if (!issuer) {
|
|
29
29
|
console.warn('[TheranovaAuth] Cannot perform global logout: issuer not provided');
|
|
30
30
|
return null;
|
|
31
31
|
}
|
|
32
|
-
// Get ID token from options or storage
|
|
33
|
-
let idTokenHint = idToken;
|
|
34
|
-
if (!idTokenHint) {
|
|
35
|
-
const tm = tokenManager || new TokenManager(storageKey);
|
|
36
|
-
idTokenHint = tm.getIdToken() || undefined;
|
|
37
|
-
}
|
|
38
32
|
// Build end_session URL
|
|
33
|
+
// client_id 사용 (id_token_hint는 만료된 토큰일 수 있어서 제외)
|
|
39
34
|
const url = new URL('/session/end', issuer);
|
|
40
|
-
if (
|
|
41
|
-
url.searchParams.set('
|
|
35
|
+
if (clientId) {
|
|
36
|
+
url.searchParams.set('client_id', clientId);
|
|
42
37
|
}
|
|
43
38
|
if (postLogoutRedirectUri) {
|
|
44
39
|
url.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri);
|
|
@@ -56,5 +51,12 @@ export function logoutAndRedirect(options) {
|
|
|
56
51
|
if (logoutUrl && typeof window !== 'undefined') {
|
|
57
52
|
window.location.href = logoutUrl;
|
|
58
53
|
}
|
|
54
|
+
else {
|
|
55
|
+
// Fallback: 로컬 로그아웃만 수행하고 홈으로 이동
|
|
56
|
+
logout(options);
|
|
57
|
+
if (typeof window !== 'undefined') {
|
|
58
|
+
window.location.href = options.postLogoutRedirectUri || '/';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
59
61
|
}
|
|
60
62
|
//# sourceMappingURL=logout.js.map
|
package/src/core/logout.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/logout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe/C;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,UAAyB,EAAE;IAChD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,IAAI,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAClF,YAAY,CAAC,KAAK,EAAE,CAAC;IAErB,4BAA4B;IAC5B,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;QAC1C,cAAc,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC1C,cAAc,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAAsB;IACjD,MAAM,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../../../../libs/theranova/auth-sdk/src/core/logout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAe/C;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,UAAyB,EAAE;IAChD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,IAAI,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAClF,YAAY,CAAC,KAAK,EAAE,CAAC;IAErB,4BAA4B;IAC5B,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;QAC1C,cAAc,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAC1C,cAAc,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,OAAsB;IACjD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAEtF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,wBAAwB;IACxB,iDAAiD;IACjD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IAE5C,IAAI,QAAQ,EAAE,CAAC;QACb,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,qBAAqB,EAAE,CAAC;QAC1B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,0BAA0B,EAAE,qBAAqB,CAAC,CAAC;IAC1E,CAAC;IAED,qBAAqB;IACrB,MAAM,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC;IAErC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAsB;IACtD,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAExC,IAAI,SAAS,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAC/C,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,iCAAiC;QACjC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,OAAO,CAAC,qBAAqB,IAAI,GAAG,CAAC;QAC9D,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/src/index.d.ts
CHANGED
|
@@ -6,12 +6,19 @@
|
|
|
6
6
|
* ```typescript
|
|
7
7
|
* import { TheranovaAuth } from '@theranova/auth-sdk';
|
|
8
8
|
*
|
|
9
|
+
* // 프로덕션 - issuer 생략 (기본값: https://auth.theranova.co.kr)
|
|
9
10
|
* const auth = new TheranovaAuth({
|
|
10
|
-
* issuer: 'https://auth.theranova.com',
|
|
11
11
|
* clientId: 'my-app',
|
|
12
12
|
* redirectUri: 'https://my-app.com/callback',
|
|
13
13
|
* });
|
|
14
14
|
*
|
|
15
|
+
* // 개발 환경 - issuer override
|
|
16
|
+
* const authDev = new TheranovaAuth({
|
|
17
|
+
* clientId: 'my-app',
|
|
18
|
+
* redirectUri: 'http://localhost:4200/callback',
|
|
19
|
+
* issuer: 'http://localhost:3001', // 로컬 Auth 서버
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
15
22
|
* // Start login flow
|
|
16
23
|
* await auth.login();
|
|
17
24
|
*
|
|
@@ -19,10 +26,10 @@
|
|
|
19
26
|
* await auth.handleCallback();
|
|
20
27
|
*
|
|
21
28
|
* // Get current user
|
|
22
|
-
* const user =
|
|
29
|
+
* const user = auth.getUserInfo();
|
|
23
30
|
*
|
|
24
31
|
* // Logout
|
|
25
|
-
*
|
|
32
|
+
* auth.logout();
|
|
26
33
|
* ```
|
|
27
34
|
*/
|
|
28
35
|
export { TheranovaAuth, type TheranovaAuthConfig, type TheranovaAuthTokens } from './core/TheranovaAuth';
|
package/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../libs/theranova/auth-sdk/src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../libs/theranova/auth-sdk/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACzG,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
package/src/index.js
CHANGED
|
@@ -6,12 +6,19 @@
|
|
|
6
6
|
* ```typescript
|
|
7
7
|
* import { TheranovaAuth } from '@theranova/auth-sdk';
|
|
8
8
|
*
|
|
9
|
+
* // 프로덕션 - issuer 생략 (기본값: https://auth.theranova.co.kr)
|
|
9
10
|
* const auth = new TheranovaAuth({
|
|
10
|
-
* issuer: 'https://auth.theranova.com',
|
|
11
11
|
* clientId: 'my-app',
|
|
12
12
|
* redirectUri: 'https://my-app.com/callback',
|
|
13
13
|
* });
|
|
14
14
|
*
|
|
15
|
+
* // 개발 환경 - issuer override
|
|
16
|
+
* const authDev = new TheranovaAuth({
|
|
17
|
+
* clientId: 'my-app',
|
|
18
|
+
* redirectUri: 'http://localhost:4200/callback',
|
|
19
|
+
* issuer: 'http://localhost:3001', // 로컬 Auth 서버
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
15
22
|
* // Start login flow
|
|
16
23
|
* await auth.login();
|
|
17
24
|
*
|
|
@@ -19,10 +26,10 @@
|
|
|
19
26
|
* await auth.handleCallback();
|
|
20
27
|
*
|
|
21
28
|
* // Get current user
|
|
22
|
-
* const user =
|
|
29
|
+
* const user = auth.getUserInfo();
|
|
23
30
|
*
|
|
24
31
|
* // Logout
|
|
25
|
-
*
|
|
32
|
+
* auth.logout();
|
|
26
33
|
* ```
|
|
27
34
|
*/
|
|
28
35
|
export { TheranovaAuth } from './core/TheranovaAuth';
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/theranova/auth-sdk/src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/theranova/auth-sdk/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,aAAa,EAAsD,MAAM,sBAAsB,CAAC;AACzG,OAAO,EAAE,YAAY,EAAqB,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAsB,MAAM,eAAe,CAAC"}
|