@autonomous-ai/auth-sdk 1.0.7

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.
Files changed (46) hide show
  1. package/README.md +300 -0
  2. package/dist/client.d.ts +60 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +224 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +5 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/pkce.d.ts +34 -0
  11. package/dist/pkce.d.ts.map +1 -0
  12. package/dist/pkce.js +85 -0
  13. package/dist/pkce.js.map +1 -0
  14. package/dist/react/AuthProvider.d.ts +25 -0
  15. package/dist/react/AuthProvider.d.ts.map +1 -0
  16. package/dist/react/AuthProvider.js +111 -0
  17. package/dist/react/AuthProvider.js.map +1 -0
  18. package/dist/react/index.d.ts +6 -0
  19. package/dist/react/index.d.ts.map +1 -0
  20. package/dist/react/index.js +5 -0
  21. package/dist/react/index.js.map +1 -0
  22. package/dist/react/useAuth.d.ts +21 -0
  23. package/dist/react/useAuth.d.ts.map +1 -0
  24. package/dist/react/useAuth.js +23 -0
  25. package/dist/react/useAuth.js.map +1 -0
  26. package/dist/react/useCallback.d.ts +31 -0
  27. package/dist/react/useCallback.d.ts.map +1 -0
  28. package/dist/react/useCallback.js +78 -0
  29. package/dist/react/useCallback.js.map +1 -0
  30. package/dist/react/useUser.d.ts +22 -0
  31. package/dist/react/useUser.d.ts.map +1 -0
  32. package/dist/react/useUser.js +25 -0
  33. package/dist/react/useUser.js.map +1 -0
  34. package/dist/storage.d.ts +49 -0
  35. package/dist/storage.d.ts.map +1 -0
  36. package/dist/storage.js +139 -0
  37. package/dist/storage.js.map +1 -0
  38. package/dist/types.d.ts +157 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +2 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/version.d.ts +5 -0
  43. package/dist/version.d.ts.map +1 -0
  44. package/dist/version.js +5 -0
  45. package/dist/version.js.map +1 -0
  46. package/package.json +62 -0
package/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # @autonomous-ai/auth-sdk
2
+
3
+ Client SDK for the auth-service SSO flow — OAuth2 Authorization Code + PKCE (S256), with first-class React bindings.
4
+
5
+ - **Zero runtime dependencies** — React is an optional peer dependency
6
+ - **ESM only**, ships TypeScript types
7
+ - Automatic token refresh before expiry
8
+ - Post-login redirect via `nextUrl`, no server-side changes needed
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @autonomous-ai/auth-sdk
14
+ ```
15
+
16
+ React is optional — only needed if you import `@autonomous-ai/auth-sdk/react`:
17
+
18
+ ```bash
19
+ npm install react # >= 18
20
+ ```
21
+
22
+ ### Local development
23
+
24
+ ```bash
25
+ npm install && npm run build
26
+ npm link # in this repo
27
+ npm link @autonomous-ai/auth-sdk # in the consuming app
28
+ ```
29
+
30
+ ## Entry points
31
+
32
+ | Import path | Contents |
33
+ | ------------------------------- | ---------------------------------------------------- |
34
+ | `@autonomous-ai/auth-sdk` | `AuthClient`, `TokenManager`, PKCE helpers, all types |
35
+ | `@autonomous-ai/auth-sdk/react` | `AuthProvider`, `useAuth`, `useUser`, `useAuthCallback` |
36
+
37
+ ## Quick Start (React)
38
+
39
+ ### 1. Wrap your app with AuthProvider
40
+
41
+ Define `authConfig` outside the component (or memoize it) — a new object identity on every render re-triggers the provider's effects.
42
+
43
+ ```tsx
44
+ import { AuthProvider } from "@autonomous-ai/auth-sdk/react";
45
+
46
+ const authConfig = {
47
+ ssoUrl: "https://sso.example.com",
48
+ clientId: "my-app",
49
+ redirectUri: "https://app.example.com/callback",
50
+ scope: "openid profile email",
51
+ };
52
+
53
+ function App() {
54
+ return (
55
+ <AuthProvider config={authConfig}>
56
+ <YourApp />
57
+ </AuthProvider>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ### 2. Use the hooks
63
+
64
+ ```tsx
65
+ import { useAuth, useUser } from "@autonomous-ai/auth-sdk/react";
66
+
67
+ function LoginButton() {
68
+ const { isAuthenticated, login, logout, isLoading } = useAuth();
69
+
70
+ if (isLoading) return <div>Loading...</div>;
71
+
72
+ if (isAuthenticated) {
73
+ return <button onClick={() => logout()}>Logout</button>;
74
+ }
75
+
76
+ return <button onClick={() => login()}>Login with SSO</button>;
77
+ }
78
+
79
+ function UserProfile() {
80
+ const user = useUser();
81
+
82
+ if (!user) return null;
83
+
84
+ return <p>Welcome, {user.fullName || user.email}!</p>;
85
+ }
86
+ ```
87
+
88
+ ### 3. Handle the OAuth2 callback
89
+
90
+ Mount this on the route you registered as `redirectUri`. The hook reads `code` / `state` from the URL, exchanges them for tokens, and is guarded against React StrictMode double-invocation.
91
+
92
+ ```tsx
93
+ import { useEffect } from "react";
94
+ import { useAuthCallback, useAuth } from "@autonomous-ai/auth-sdk/react";
95
+ import { useNavigate } from "react-router-dom";
96
+
97
+ function CallbackPage() {
98
+ const navigate = useNavigate();
99
+ const { refreshAuthState } = useAuth();
100
+ const { isLoading, error, success, nextUrl } = useAuthCallback(authConfig);
101
+
102
+ useEffect(() => {
103
+ if (success) {
104
+ refreshAuthState(); // re-read tokens written by the callback
105
+ navigate(nextUrl || "/");
106
+ }
107
+ }, [success, nextUrl, navigate, refreshAuthState]);
108
+
109
+ if (isLoading) return <div>Processing login...</div>;
110
+ if (error) return <div>Login failed: {error}</div>;
111
+
112
+ return null;
113
+ }
114
+ ```
115
+
116
+ ### 4. Post-login redirect (`nextUrl`)
117
+
118
+ Pass `nextUrl` to `login()` to send the user back to the page they started from. It is stored in `sessionStorage` before the SSO redirect and returned by `useAuthCallback` after a successful exchange.
119
+
120
+ ```tsx
121
+ import { useEffect } from "react";
122
+ import { useAuth } from "@autonomous-ai/auth-sdk/react";
123
+ import { useLocation } from "react-router-dom";
124
+
125
+ function ProtectedPage() {
126
+ const location = useLocation();
127
+ const { isAuthenticated, isLoading, login } = useAuth();
128
+
129
+ useEffect(() => {
130
+ if (!isLoading && !isAuthenticated) {
131
+ login({
132
+ nextUrl: `${location.pathname}${location.search}${location.hash}`,
133
+ });
134
+ }
135
+ }, [isAuthenticated, isLoading, login, location]);
136
+
137
+ if (isLoading || !isAuthenticated) {
138
+ return <div>Redirecting to login...</div>;
139
+ }
140
+
141
+ return <div>Protected content</div>;
142
+ }
143
+ ```
144
+
145
+ ## Vanilla JavaScript / TypeScript
146
+
147
+ ```typescript
148
+ import { AuthClient } from "@autonomous-ai/auth-sdk";
149
+
150
+ const client = new AuthClient({
151
+ ssoUrl: "https://sso.example.com",
152
+ clientId: "my-app",
153
+ redirectUri: "https://app.example.com/callback",
154
+ scope: "openid profile email",
155
+ });
156
+
157
+ // Start login (redirects the browser to SSO)
158
+ await client.authorize({ nextUrl: "/dashboard" });
159
+
160
+ // On the callback page
161
+ const params = new URLSearchParams(window.location.search);
162
+ const result = await client.handleCallback(
163
+ params.get("code")!,
164
+ params.get("state")!
165
+ );
166
+
167
+ if (result.success) {
168
+ if (result.nextUrl) window.location.href = result.nextUrl;
169
+ } else {
170
+ console.error(result.error);
171
+ }
172
+
173
+ // Auth status
174
+ if (client.isAuthenticated()) {
175
+ console.log("User:", client.getUser());
176
+ }
177
+
178
+ // Access token for API calls — refreshes automatically if expired
179
+ const token = await client.getValidAccessToken();
180
+ await fetch("/api/me", { headers: { Authorization: `Bearer ${token}` } });
181
+
182
+ // Logout (clears tokens and redirects to SSO logout)
183
+ client.logout();
184
+ ```
185
+
186
+ ## API Reference
187
+
188
+ ### AuthClient
189
+
190
+ | Method | Returns | Description |
191
+ | ------------------------------- | -------------------------- | ---------------------------------------- |
192
+ | `authorize(options?)` | `Promise<void>` | Start OAuth2 login flow (redirects away) |
193
+ | `handleCallback(code, state)` | `Promise<CallbackResult>` | Exchange authorization code for tokens |
194
+ | `refreshToken()` | `Promise<TokenResponse>` | Refresh the access token |
195
+ | `logout(redirectUri?)` | `void` | Clear tokens and redirect to SSO logout |
196
+ | `isAuthenticated()` | `boolean` | Whether a valid session exists |
197
+ | `getAccessToken()` | `string \| null` | Current access token |
198
+ | `getRefreshToken()` | `string \| null` | Current refresh token |
199
+ | `getUser()` | `User \| null` | User decoded from the JWT |
200
+ | `isTokenExpired(buffer = 60)` | `boolean` | Expiry check with a seconds buffer |
201
+ | `getValidAccessToken()` | `Promise<string>` | Token, refreshed if expired |
202
+ | `clearTokens()` | `void` | Clear tokens without an SSO logout |
203
+
204
+ `createAuthClient(config)` is a factory shorthand for `new AuthClient(config)`.
205
+
206
+ ### AuthConfig
207
+
208
+ | Option | Type | Default | Description |
209
+ | ------------- | -------------- | ---------------- | ------------------------------------ |
210
+ | `ssoUrl` | `string` | required | SSO server base URL |
211
+ | `clientId` | `string` | required | OAuth2 client ID |
212
+ | `redirectUri` | `string` | required | Callback URL registered with the SSO |
213
+ | `scope` | `string?` | - | Space-separated scopes |
214
+ | `storage` | `TokenStorage?` | `localStorage` | Custom token storage |
215
+
216
+ ### AuthorizeOptions
217
+
218
+ | Option | Type | Description |
219
+ | ----------- | --------------------------------------- | ----------------------------------------- |
220
+ | `prompt` | `'select_account' \| 'none' \| 'login'` | Force account selection or silent auth |
221
+ | `loginHint` | `string` | Pre-fill email for login |
222
+ | `nextUrl` | `string` | URL to redirect to after successful login |
223
+
224
+ ### User
225
+
226
+ Parsed from the JWT's `ext_info` claim.
227
+
228
+ | Field | Type | Description |
229
+ | -------------------- | ----------- | ------------------------- |
230
+ | `id` | `string` | User ID |
231
+ | `email` | `string` | User email |
232
+ | `fullName` | `string?` | Full name |
233
+ | `code` | `string?` | User code |
234
+ | `roles` | `string[]?` | User roles |
235
+ | `scope` | `string?` | Granted scope |
236
+ | `companyDomain` | `string?` | Company domain |
237
+ | `companyDomainType` | `string?` | Company domain type |
238
+ | `isEppUser` | `boolean?` | Employee Purchase Program |
239
+ | `vendorId` | `string?` | Vendor ID |
240
+ | `vendorCode` | `string?` | Vendor code |
241
+ | `vendorName` | `string?` | Vendor name |
242
+ | `referralCode` | `string?` | Referral code |
243
+
244
+ ### CallbackResult
245
+
246
+ | Field | Type | Description |
247
+ | --------- | ----------------- | -------------------------------------- |
248
+ | `success` | `boolean` | Whether the code exchange succeeded |
249
+ | `tokens` | `TokenResponse?` | Tokens returned by auth-service |
250
+ | `error` | `string?` | Error message when `success` is false |
251
+ | `nextUrl` | `string?` | Post-login redirect target |
252
+
253
+ ### React hooks
254
+
255
+ | Hook | Returns | Description |
256
+ | ------------------------- | ----------------------------------------------------------- | ---------------------- |
257
+ | `useAuth()` | `AuthContextValue` | Auth state and actions |
258
+ | `useUser()` | `User \| null` | Current user |
259
+ | `useAuthCallback(config)` | `{ isLoading, error, success, result, nextUrl }` | Handle OAuth2 callback |
260
+
261
+ `useAuth()` returns `isAuthenticated`, `isLoading`, `user`, `error`, plus `login()`, `logout()`, `getAccessToken()`, `refreshToken()` and `refreshAuthState()`.
262
+
263
+ `useAuthCallback` creates its own `AuthClient` and works outside `AuthProvider` — but call `refreshAuthState()` afterwards so the provider picks up the new tokens.
264
+
265
+ ### AuthProvider props
266
+
267
+ | Prop | Type | Default | Description |
268
+ | --------------- | ------------ | -------- | -------------------------------- |
269
+ | `config` | `AuthConfig` | required | Auth configuration |
270
+ | `autoRefresh` | `boolean` | `true` | Auto-refresh tokens |
271
+ | `refreshBuffer` | `number` | `60` | Seconds before expiry to refresh |
272
+ | `onAuthChange` | `function` | - | Called on auth state change |
273
+
274
+ ## Custom storage
275
+
276
+ Tokens go to `localStorage` by default. Supply any object implementing `TokenStorage` to change that — e.g. `sessionStorage` so the session dies with the tab:
277
+
278
+ ```typescript
279
+ const client = new AuthClient({
280
+ ...config,
281
+ storage: {
282
+ getItem: (key) => sessionStorage.getItem(key),
283
+ setItem: (key, value) => sessionStorage.setItem(key, value),
284
+ removeItem: (key) => sessionStorage.removeItem(key),
285
+ },
286
+ });
287
+ ```
288
+
289
+ The PKCE verifier and `state` always use `sessionStorage`, regardless of this setting.
290
+
291
+ ## Security
292
+
293
+ - PKCE (S256) prevents authorization code interception
294
+ - `state` parameter for CSRF protection, validated on callback
295
+ - PKCE verifier kept in `sessionStorage`, never in `localStorage`
296
+ - Tokens refreshed automatically before expiry (`refreshBuffer`)
297
+
298
+ ## License
299
+
300
+ MIT
@@ -0,0 +1,60 @@
1
+ import type { AuthConfig, AuthorizeOptions, CallbackResult, TokenResponse, User } from './types';
2
+ /**
3
+ * Auth Client for OAuth2 SSO flow with PKCE
4
+ */
5
+ export declare class AuthClient {
6
+ private config;
7
+ private tokenManager;
8
+ constructor(config: AuthConfig);
9
+ /**
10
+ * Start OAuth2 authorization flow with PKCE
11
+ * Redirects the browser to SSO login page
12
+ */
13
+ authorize(options?: AuthorizeOptions): Promise<void>;
14
+ /**
15
+ * Handle OAuth2 callback - exchange code for tokens
16
+ * Call this from your callback page
17
+ */
18
+ handleCallback(code: string, state: string): Promise<CallbackResult>;
19
+ /**
20
+ * Refresh access token using refresh token
21
+ */
22
+ refreshToken(): Promise<TokenResponse>;
23
+ /**
24
+ * Logout - clears tokens and redirects to SSO logout
25
+ */
26
+ logout(redirectUri?: string): void;
27
+ /**
28
+ * Check if user is authenticated
29
+ */
30
+ isAuthenticated(): boolean;
31
+ /**
32
+ * Get current access token
33
+ */
34
+ getAccessToken(): string | null;
35
+ /**
36
+ * Get current refresh token
37
+ */
38
+ getRefreshToken(): string | null;
39
+ /**
40
+ * Get user info from current token
41
+ */
42
+ getUser(): User | null;
43
+ /**
44
+ * Check if token is expired or about to expire
45
+ */
46
+ isTokenExpired(bufferSeconds?: number): boolean;
47
+ /**
48
+ * Get a valid access token, refreshing if needed
49
+ */
50
+ getValidAccessToken(): Promise<string>;
51
+ /**
52
+ * Clear all stored tokens (local logout without SSO redirect)
53
+ */
54
+ clearTokens(): void;
55
+ }
56
+ /**
57
+ * Create a new AuthClient instance
58
+ */
59
+ export declare function createAuthClient(config: AuthConfig): AuthClient;
60
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,IAAI,EACL,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAe;gBAEvB,MAAM,EAAE,UAAU;IAS9B;;;OAGG;IACG,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC1D;;;OAGG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAqE1E;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC;IAiC5C;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAqBlC;;OAEG;IACH,eAAe,IAAI,OAAO;IAI1B;;OAEG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,OAAO,IAAI,IAAI,GAAG,IAAI;IAItB;;OAEG;IACH,cAAc,CAAC,aAAa,GAAE,MAAW,GAAG,OAAO;IAInD;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAa5C;;OAEG;IACH,WAAW,IAAI,IAAI;CAIpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAE/D"}
package/dist/client.js ADDED
@@ -0,0 +1,224 @@
1
+ import { generateCodeChallenge, generateCodeVerifier, generateState, pkceStorage } from './pkce';
2
+ import { TokenManager, defaultStorage } from './storage';
3
+ import { SDK_VERSION } from './version';
4
+ /**
5
+ * Auth Client for OAuth2 SSO flow with PKCE
6
+ */
7
+ export class AuthClient {
8
+ constructor(config) {
9
+ this.config = {
10
+ scope: 'openid profile email',
11
+ storage: defaultStorage,
12
+ ...config,
13
+ };
14
+ this.tokenManager = new TokenManager(this.config.storage);
15
+ }
16
+ /**
17
+ * Start OAuth2 authorization flow with PKCE
18
+ * Redirects the browser to SSO login page
19
+ */
20
+ async authorize(options) {
21
+ // Generate and store PKCE code verifier
22
+ const codeVerifier = generateCodeVerifier();
23
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
24
+ pkceStorage.setCodeVerifier(codeVerifier);
25
+ // Generate and store state for CSRF protection
26
+ const state = generateState();
27
+ pkceStorage.setState(state);
28
+ // Build authorization URL
29
+ const params = new URLSearchParams({
30
+ response_type: 'code',
31
+ client_id: this.config.clientId,
32
+ redirect_uri: this.config.redirectUri,
33
+ scope: this.config.scope,
34
+ state: state,
35
+ code_challenge: codeChallenge,
36
+ code_challenge_method: 'S256',
37
+ autonomous_sdk_version: SDK_VERSION,
38
+ });
39
+ // Store next URL for post-login redirect
40
+ if (options?.nextUrl) {
41
+ pkceStorage.setNextUrl(options.nextUrl);
42
+ }
43
+ // Add optional parameters
44
+ if (options?.prompt) {
45
+ params.set('prompt', options.prompt);
46
+ }
47
+ if (options?.loginHint) {
48
+ params.set('login_hint', options.loginHint);
49
+ }
50
+ // Redirect to SSO authorization endpoint
51
+ window.location.href = `${this.config.ssoUrl}/oauth2/authorize?${params.toString()}`;
52
+ }
53
+ /**
54
+ * Handle OAuth2 callback - exchange code for tokens
55
+ * Call this from your callback page
56
+ */
57
+ async handleCallback(code, state) {
58
+ try {
59
+ // Verify state to prevent CSRF
60
+ const storedState = pkceStorage.getState();
61
+ if (!storedState || storedState !== state) {
62
+ return {
63
+ success: false,
64
+ error: 'Invalid state parameter - possible CSRF attack',
65
+ };
66
+ }
67
+ // Get PKCE code verifier
68
+ const codeVerifier = pkceStorage.getCodeVerifier();
69
+ if (!codeVerifier) {
70
+ return {
71
+ success: false,
72
+ error: 'Missing code verifier - PKCE flow incomplete',
73
+ };
74
+ }
75
+ // Exchange code for tokens
76
+ const response = await fetch(`${this.config.ssoUrl}/oauth2/token`, {
77
+ method: 'POST',
78
+ headers: {
79
+ 'Content-Type': 'application/x-www-form-urlencoded',
80
+ },
81
+ body: new URLSearchParams({
82
+ grant_type: 'authorization_code',
83
+ code: code,
84
+ redirect_uri: this.config.redirectUri,
85
+ client_id: this.config.clientId,
86
+ code_verifier: codeVerifier,
87
+ autonomous_sdk_version: SDK_VERSION,
88
+ }),
89
+ });
90
+ // Get next URL before clearing PKCE storage
91
+ const nextUrl = pkceStorage.getNextUrl() || undefined;
92
+ // Clear PKCE storage after use
93
+ pkceStorage.clear();
94
+ const result = await response.json();
95
+ // Check for OAuth2 error response
96
+ if (!result.access_token) {
97
+ return {
98
+ success: false,
99
+ error: 'Token exchange failed',
100
+ };
101
+ }
102
+ // Store tokens
103
+ this.tokenManager.setTokens(result);
104
+ return {
105
+ success: true,
106
+ tokens: result,
107
+ nextUrl,
108
+ };
109
+ }
110
+ catch (err) {
111
+ pkceStorage.clear();
112
+ return {
113
+ success: false,
114
+ error: err instanceof Error ? err.message : 'Unknown error during callback',
115
+ };
116
+ }
117
+ }
118
+ /**
119
+ * Refresh access token using refresh token
120
+ */
121
+ async refreshToken() {
122
+ const refreshToken = this.tokenManager.getRefreshToken();
123
+ if (!refreshToken) {
124
+ throw new Error('No refresh token available');
125
+ }
126
+ const response = await fetch(`${this.config.ssoUrl}/oauth2/token`, {
127
+ method: 'POST',
128
+ headers: {
129
+ 'Content-Type': 'application/x-www-form-urlencoded',
130
+ },
131
+ body: new URLSearchParams({
132
+ grant_type: 'refresh_token',
133
+ refresh_token: refreshToken,
134
+ client_id: this.config.clientId,
135
+ autonomous_sdk_version: SDK_VERSION,
136
+ }),
137
+ });
138
+ const result = await response.json();
139
+ // Check for OAuth2 error response
140
+ if (!result.access_token) {
141
+ // Clear tokens on refresh failure
142
+ this.tokenManager.clearTokens();
143
+ throw new Error('Token refresh failed');
144
+ }
145
+ this.tokenManager.setTokens(result);
146
+ return result;
147
+ }
148
+ /**
149
+ * Logout - clears tokens and redirects to SSO logout
150
+ */
151
+ logout(redirectUri) {
152
+ const postLogoutRedirectUri = redirectUri || window.location.origin;
153
+ const idToken = this.tokenManager.getAccessToken();
154
+ // Clear local tokens
155
+ this.tokenManager.clearTokens();
156
+ pkceStorage.clear();
157
+ // Build logout URL
158
+ const params = new URLSearchParams({
159
+ post_logout_redirect_uri: postLogoutRedirectUri,
160
+ });
161
+ if (idToken) {
162
+ params.set('id_token_hint', idToken);
163
+ }
164
+ // Redirect to SSO logout endpoint
165
+ window.location.href = `${this.config.ssoUrl}/oauth2/logout?${params.toString()}`;
166
+ }
167
+ /**
168
+ * Check if user is authenticated
169
+ */
170
+ isAuthenticated() {
171
+ return this.tokenManager.isAuthenticated();
172
+ }
173
+ /**
174
+ * Get current access token
175
+ */
176
+ getAccessToken() {
177
+ return this.tokenManager.getAccessToken();
178
+ }
179
+ /**
180
+ * Get current refresh token
181
+ */
182
+ getRefreshToken() {
183
+ return this.tokenManager.getRefreshToken();
184
+ }
185
+ /**
186
+ * Get user info from current token
187
+ */
188
+ getUser() {
189
+ return this.tokenManager.getUser();
190
+ }
191
+ /**
192
+ * Check if token is expired or about to expire
193
+ */
194
+ isTokenExpired(bufferSeconds = 60) {
195
+ return this.tokenManager.isTokenExpired(bufferSeconds);
196
+ }
197
+ /**
198
+ * Get a valid access token, refreshing if needed
199
+ */
200
+ async getValidAccessToken() {
201
+ if (this.isTokenExpired()) {
202
+ await this.refreshToken();
203
+ }
204
+ const token = this.getAccessToken();
205
+ if (!token) {
206
+ throw new Error('No access token available');
207
+ }
208
+ return token;
209
+ }
210
+ /**
211
+ * Clear all stored tokens (local logout without SSO redirect)
212
+ */
213
+ clearTokens() {
214
+ this.tokenManager.clearTokens();
215
+ pkceStorage.clear();
216
+ }
217
+ }
218
+ /**
219
+ * Create a new AuthClient instance
220
+ */
221
+ export function createAuthClient(config) {
222
+ return new AuthClient(config);
223
+ }
224
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { AuthClient, createAuthClient } from './client';
2
+ export { TokenManager, defaultStorage } from './storage';
3
+ export { generateCodeVerifier, generateCodeChallenge, generateState, pkceStorage, } from './pkce';
4
+ export type { AuthConfig, TokenStorage, AuthorizeOptions, TokenResponse, OAuth2Error, ApiResponse, JwtPayload, JwtExtInfo, User, AuthState, AuthContextValue, CallbackResult, } from './types';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,WAAW,GACZ,MAAM,QAAQ,CAAC;AAGhB,YAAY,EACV,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,UAAU,EACV,IAAI,EACJ,SAAS,EACT,gBAAgB,EAChB,cAAc,GACf,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Core exports
2
+ export { AuthClient, createAuthClient } from './client';
3
+ export { TokenManager, defaultStorage } from './storage';
4
+ export { generateCodeVerifier, generateCodeChallenge, generateState, pkceStorage, } from './pkce';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,WAAW,GACZ,MAAM,QAAQ,CAAC"}
package/dist/pkce.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * PKCE (Proof Key for Code Exchange) utilities
3
+ * Implements RFC 7636 for OAuth2 authorization code flow security
4
+ */
5
+ /**
6
+ * Generate a cryptographically random code verifier (43-128 chars)
7
+ */
8
+ export declare function generateCodeVerifier(): string;
9
+ /**
10
+ * Generate code challenge from verifier using SHA-256 (S256 method)
11
+ */
12
+ export declare function generateCodeChallenge(verifier: string): Promise<string>;
13
+ /**
14
+ * Generate random state for CSRF protection
15
+ */
16
+ export declare function generateState(): string;
17
+ /**
18
+ * PKCE and state storage using sessionStorage
19
+ * (More secure than localStorage for PKCE verifier)
20
+ */
21
+ export declare const pkceStorage: {
22
+ setCodeVerifier(verifier: string): void;
23
+ getCodeVerifier(): string | null;
24
+ clearCodeVerifier(): void;
25
+ setState(state: string): void;
26
+ getState(): string | null;
27
+ clearState(): void;
28
+ setNextUrl(url: string): void;
29
+ getNextUrl(): string | null;
30
+ clearNextUrl(): void;
31
+ /** Clear all PKCE-related data */
32
+ clear(): void;
33
+ };
34
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../src/pkce.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK7E;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAgBD;;;GAGG;AACH,eAAO,MAAM,WAAW;8BACI,MAAM,GAAG,IAAI;uBAIpB,MAAM,GAAG,IAAI;yBAIX,IAAI;oBAIT,MAAM,GAAG,IAAI;gBAIjB,MAAM,GAAG,IAAI;kBAIX,IAAI;oBAIF,MAAM,GAAG,IAAI;kBAIf,MAAM,GAAG,IAAI;oBAIX,IAAI;IAIpB,kCAAkC;aACzB,IAAI;CAKd,CAAC"}