@drmhse/sso-sdk 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -299
- package/dist/index.d.mts +0 -1
- package/dist/index.d.ts +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,14 +4,12 @@ A zero-dependency, strongly-typed TypeScript SDK for interacting with the multi-
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- **Comprehensive Documentation**: Full TSDoc comments for excellent IDE support
|
|
14
|
-
- **Modern**: Supports Node.js 18+ and all modern browsers
|
|
7
|
+
- **Zero Dependencies**: Built on native `fetch` API - no external dependencies.
|
|
8
|
+
- **Framework Agnostic**: Pure TypeScript - works in any JavaScript environment.
|
|
9
|
+
- **Strongly Typed**: Complete TypeScript definitions for all API endpoints.
|
|
10
|
+
- **Stateless Design**: No internal state management - integrates with any state solution.
|
|
11
|
+
- **Predictable Error Handling**: Custom `SsoApiError` class with structured error information.
|
|
12
|
+
- **Modern**: Supports Node.js 18+ and all modern browsers.
|
|
15
13
|
|
|
16
14
|
## Installation
|
|
17
15
|
|
|
@@ -22,12 +20,12 @@ npm install @drmhse/sso-sdk
|
|
|
22
20
|
## Quick Start
|
|
23
21
|
|
|
24
22
|
```typescript
|
|
25
|
-
import { SsoClient } from '@drmhse/sso-sdk';
|
|
23
|
+
import { SsoClient, SsoApiError } from '@drmhse/sso-sdk';
|
|
26
24
|
|
|
27
25
|
// Initialize the client
|
|
28
26
|
const sso = new SsoClient({
|
|
29
27
|
baseURL: 'https://sso.example.com',
|
|
30
|
-
token: localStorage.getItem('
|
|
28
|
+
token: localStorage.getItem('sso_token') // Optional initial token
|
|
31
29
|
});
|
|
32
30
|
|
|
33
31
|
// Use the SDK
|
|
@@ -53,7 +51,7 @@ async function example() {
|
|
|
53
51
|
### End-User OAuth Login
|
|
54
52
|
|
|
55
53
|
```typescript
|
|
56
|
-
// Redirect user to OAuth provider
|
|
54
|
+
// 1. Redirect user to OAuth provider
|
|
57
55
|
const loginUrl = sso.auth.getLoginUrl('github', {
|
|
58
56
|
org: 'acme-corp',
|
|
59
57
|
service: 'main-app',
|
|
@@ -61,11 +59,15 @@ const loginUrl = sso.auth.getLoginUrl('github', {
|
|
|
61
59
|
});
|
|
62
60
|
window.location.href = loginUrl;
|
|
63
61
|
|
|
64
|
-
// In your callback handler
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
// 2. In your callback handler, extract both tokens from the URL
|
|
63
|
+
const params = new URLSearchParams(window.location.search);
|
|
64
|
+
const accessToken = params.get('access_token');
|
|
65
|
+
const refreshToken = params.get('refresh_token');
|
|
66
|
+
|
|
67
|
+
if (accessToken && refreshToken) {
|
|
68
|
+
sso.setAuthToken(accessToken);
|
|
69
|
+
localStorage.setItem('sso_token', accessToken);
|
|
70
|
+
localStorage.setItem('sso_refresh_token', refreshToken);
|
|
69
71
|
}
|
|
70
72
|
```
|
|
71
73
|
|
|
@@ -73,43 +75,66 @@ if (token) {
|
|
|
73
75
|
|
|
74
76
|
```typescript
|
|
75
77
|
const adminUrl = sso.auth.getAdminLoginUrl('github', {
|
|
76
|
-
org_slug: 'acme-corp' // Optional
|
|
78
|
+
org_slug: 'acme-corp' // Optional: directs user to a specific org dashboard after login
|
|
77
79
|
});
|
|
78
80
|
window.location.href = adminUrl;
|
|
79
81
|
```
|
|
80
82
|
|
|
81
83
|
### Device Flow (for CLIs)
|
|
82
84
|
|
|
85
|
+
This flow involves both the CLI and a web browser.
|
|
86
|
+
|
|
83
87
|
```typescript
|
|
84
|
-
//
|
|
88
|
+
// --- In your CLI Application ---
|
|
89
|
+
|
|
90
|
+
// 1. Request device code
|
|
85
91
|
const deviceAuth = await sso.auth.deviceCode.request({
|
|
86
92
|
client_id: 'cli-client-id',
|
|
87
93
|
org: 'acme-corp',
|
|
88
94
|
service: 'acme-cli'
|
|
89
95
|
});
|
|
90
96
|
|
|
91
|
-
console.log(`Visit ${deviceAuth.verification_uri}`);
|
|
97
|
+
console.log(`Visit: ${deviceAuth.verification_uri}`);
|
|
92
98
|
console.log(`Enter code: ${deviceAuth.user_code}`);
|
|
93
99
|
|
|
94
|
-
//
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
100
|
+
// 4. Poll for the token
|
|
101
|
+
const pollForToken = async () => {
|
|
102
|
+
// Polling logic...
|
|
103
|
+
};
|
|
104
|
+
pollForToken();
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
// --- In your Web Application at /activate ---
|
|
108
|
+
|
|
109
|
+
// 2. After user enters the code, verify it to get context
|
|
110
|
+
const context = await sso.auth.deviceCode.verify(userEnteredCode);
|
|
111
|
+
|
|
112
|
+
// 3. Redirect user to the appropriate login flow, passing the user_code
|
|
113
|
+
// This links the browser session to the device waiting for authorization.
|
|
114
|
+
const loginUrl = sso.auth.getLoginUrl('github', {
|
|
115
|
+
org: context.org_slug,
|
|
116
|
+
service: context.service_slug,
|
|
117
|
+
user_code: userEnteredCode, // CRITICAL: Pass user_code here
|
|
118
|
+
});
|
|
119
|
+
window.location.href = loginUrl; // User logs in, authorizing the device
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Refreshing Tokens
|
|
123
|
+
|
|
124
|
+
Renew an expired access token using a refresh token. This uses token rotation for enhanced security.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
try {
|
|
128
|
+
const tokens = await sso.auth.refreshToken(storedRefreshToken);
|
|
129
|
+
|
|
130
|
+
// Update tokens in your application state and storage
|
|
131
|
+
sso.setAuthToken(tokens.access_token);
|
|
132
|
+
localStorage.setItem('sso_token', tokens.access_token);
|
|
133
|
+
localStorage.setItem('sso_refresh_token', tokens.refresh_token);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
// Refresh failed, user needs to log in again
|
|
136
|
+
console.error("Token refresh failed:", error);
|
|
137
|
+
}
|
|
113
138
|
```
|
|
114
139
|
|
|
115
140
|
### Logout
|
|
@@ -117,14 +142,15 @@ const pollInterval = setInterval(async () => {
|
|
|
117
142
|
```typescript
|
|
118
143
|
await sso.auth.logout();
|
|
119
144
|
sso.setAuthToken(null);
|
|
120
|
-
localStorage.removeItem('
|
|
145
|
+
localStorage.removeItem('sso_token');
|
|
146
|
+
localStorage.removeItem('sso_refresh_token');
|
|
121
147
|
```
|
|
122
148
|
|
|
123
149
|
## API Reference
|
|
124
150
|
|
|
125
|
-
### Analytics
|
|
151
|
+
### Analytics (`sso.analytics`)
|
|
126
152
|
|
|
127
|
-
|
|
153
|
+
Provides login tracking and metrics for a specific organization.
|
|
128
154
|
|
|
129
155
|
```typescript
|
|
130
156
|
// Get login trends over time
|
|
@@ -132,20 +158,21 @@ const trends = await sso.analytics.getLoginTrends('acme-corp', {
|
|
|
132
158
|
start_date: '2025-01-01',
|
|
133
159
|
end_date: '2025-01-31'
|
|
134
160
|
});
|
|
161
|
+
```
|
|
135
162
|
|
|
136
|
-
|
|
137
|
-
const byService = await sso.analytics.getLoginsByService('acme-corp');
|
|
163
|
+
### Authentication (`sso.auth`)
|
|
138
164
|
|
|
139
|
-
|
|
140
|
-
const byProvider = await sso.analytics.getLoginsByProvider('acme-corp');
|
|
165
|
+
Handles all authentication flows, including OAuth, device flow, and token management.
|
|
141
166
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
167
|
+
```typescript
|
|
168
|
+
// Get a fresh OAuth token for an external provider (e.g., GitHub)
|
|
169
|
+
const githubToken = await sso.auth.getProviderToken('github');
|
|
170
|
+
// Use githubToken.access_token to make GitHub API calls
|
|
146
171
|
```
|
|
147
172
|
|
|
148
|
-
### Organizations
|
|
173
|
+
### Organizations (`sso.organizations`)
|
|
174
|
+
|
|
175
|
+
Manages organizations, members, and BYOO credentials.
|
|
149
176
|
|
|
150
177
|
```typescript
|
|
151
178
|
// Create organization (public endpoint)
|
|
@@ -155,35 +182,14 @@ const org = await sso.organizations.createPublic({
|
|
|
155
182
|
owner_email: 'founder@acme.com'
|
|
156
183
|
});
|
|
157
184
|
|
|
158
|
-
// List user's organizations
|
|
159
|
-
const orgs = await sso.organizations.list({ status: 'active' });
|
|
160
|
-
|
|
161
|
-
// Get organization details
|
|
162
|
-
const details = await sso.organizations.get('acme-corp');
|
|
163
|
-
|
|
164
|
-
// Update organization
|
|
165
|
-
await sso.organizations.update('acme-corp', {
|
|
166
|
-
name: 'Acme Corp Inc.'
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Manage members
|
|
170
|
-
const members = await sso.organizations.members.list('acme-corp');
|
|
171
|
-
await sso.organizations.members.updateRole('acme-corp', 'user-id', {
|
|
172
|
-
role: 'admin'
|
|
173
|
-
});
|
|
174
|
-
await sso.organizations.members.remove('acme-corp', 'user-id');
|
|
175
|
-
|
|
176
185
|
// BYOO: Set custom OAuth credentials
|
|
177
186
|
await sso.organizations.oauthCredentials.set('acme-corp', 'github', {
|
|
178
187
|
client_id: 'Iv1.abc123',
|
|
179
188
|
client_secret: 'secret-value'
|
|
180
189
|
});
|
|
181
|
-
|
|
182
|
-
// Get configured OAuth credentials
|
|
183
|
-
const creds = await sso.organizations.oauthCredentials.get('acme-corp', 'github');
|
|
184
190
|
```
|
|
185
191
|
|
|
186
|
-
|
|
192
|
+
#### End-User Management (`sso.organizations.endUsers`)
|
|
187
193
|
|
|
188
194
|
Manage your organization's customers (end-users with subscriptions).
|
|
189
195
|
|
|
@@ -194,174 +200,87 @@ const endUsers = await sso.organizations.endUsers.list('acme-corp', {
|
|
|
194
200
|
limit: 20
|
|
195
201
|
});
|
|
196
202
|
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// Revoke all active sessions for an end-user
|
|
201
|
-
const result = await sso.organizations.endUsers.revokeSessions('acme-corp', 'user-id');
|
|
203
|
+
// Revoke all active sessions for a specific end-user
|
|
204
|
+
await sso.organizations.endUsers.revokeSessions('acme-corp', 'user-id-123');
|
|
202
205
|
```
|
|
203
206
|
|
|
204
|
-
### Services
|
|
207
|
+
### Services & Plans (`sso.services`)
|
|
208
|
+
|
|
209
|
+
Manages the applications (services) and subscription plans for an organization.
|
|
205
210
|
|
|
206
211
|
```typescript
|
|
207
|
-
// Create
|
|
212
|
+
// Create a service
|
|
208
213
|
const result = await sso.services.create('acme-corp', {
|
|
209
214
|
slug: 'main-app',
|
|
210
215
|
name: 'Main Application',
|
|
211
216
|
service_type: 'web',
|
|
212
|
-
github_scopes: ['user:email', 'read:org'],
|
|
213
|
-
microsoft_scopes: ['User.Read', 'email'],
|
|
214
|
-
google_scopes: ['openid', 'email', 'profile'],
|
|
215
217
|
redirect_uris: ['https://app.acme.com/callback']
|
|
216
218
|
});
|
|
217
|
-
console.log(result.service.client_id);
|
|
218
|
-
console.log(result.usage.current_services);
|
|
219
|
-
|
|
220
|
-
// List services (returns services with usage metadata)
|
|
221
|
-
const result = await sso.services.list('acme-corp');
|
|
222
|
-
console.log(`Using ${result.usage.current_services} of ${result.usage.max_services} services`);
|
|
223
|
-
result.services.forEach(svc => console.log(svc.name, svc.client_id));
|
|
224
|
-
|
|
225
|
-
// Get service details (includes provider grants and plans)
|
|
226
|
-
const service = await sso.services.get('acme-corp', 'main-app');
|
|
227
|
-
console.log(service.service.redirect_uris);
|
|
228
|
-
console.log(service.plans);
|
|
229
|
-
|
|
230
|
-
// Update service
|
|
231
|
-
const updated = await sso.services.update('acme-corp', 'main-app', {
|
|
232
|
-
name: 'Main Application v2',
|
|
233
|
-
github_scopes: ['user:email', 'read:org', 'repo'],
|
|
234
|
-
microsoft_scopes: ['User.Read', 'email', 'Mail.Read'],
|
|
235
|
-
google_scopes: ['openid', 'email', 'profile', 'drive.readonly'],
|
|
236
|
-
redirect_uris: ['https://app.acme.com/callback', 'https://app.acme.com/oauth']
|
|
237
|
-
});
|
|
238
219
|
|
|
239
|
-
//
|
|
240
|
-
await sso.services.
|
|
241
|
-
|
|
242
|
-
// Manage plans
|
|
243
|
-
const plan = await sso.services.plans.create('acme-corp', 'main-app', {
|
|
220
|
+
// Create a subscription plan for that service
|
|
221
|
+
await sso.services.plans.create('acme-corp', 'main-app', {
|
|
244
222
|
name: 'pro',
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
features: ['api-access', '
|
|
223
|
+
price_cents: 2999, // Note: price is in cents
|
|
224
|
+
currency: 'usd',
|
|
225
|
+
features: ['api-access', 'priority-support']
|
|
248
226
|
});
|
|
249
|
-
|
|
250
|
-
// List all plans for a service
|
|
251
|
-
const plans = await sso.services.plans.list('acme-corp', 'main-app');
|
|
252
|
-
plans.forEach(plan => console.log(plan.name, plan.price_monthly));
|
|
253
227
|
```
|
|
254
228
|
|
|
255
|
-
###
|
|
229
|
+
### User Profile & Identities (`sso.user`)
|
|
256
230
|
|
|
257
|
-
|
|
258
|
-
// Send invitation
|
|
259
|
-
const invitation = await sso.invitations.create('acme-corp', {
|
|
260
|
-
invitee_email: 'newuser@example.com',
|
|
261
|
-
role: 'member'
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
// List organization's invitations
|
|
265
|
-
const orgInvites = await sso.invitations.listForOrg('acme-corp');
|
|
266
|
-
|
|
267
|
-
// List user's invitations
|
|
268
|
-
const myInvites = await sso.invitations.listForUser();
|
|
269
|
-
|
|
270
|
-
// Accept invitation
|
|
271
|
-
await sso.invitations.accept('invitation-token');
|
|
272
|
-
|
|
273
|
-
// Decline invitation
|
|
274
|
-
await sso.invitations.decline('invitation-token');
|
|
275
|
-
|
|
276
|
-
// Cancel invitation
|
|
277
|
-
await sso.invitations.cancel('acme-corp', 'invitation-id');
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### User Profile
|
|
231
|
+
Manages the authenticated user's own profile and linked social accounts.
|
|
281
232
|
|
|
282
233
|
```typescript
|
|
283
234
|
// Get profile
|
|
284
235
|
const profile = await sso.user.getProfile();
|
|
285
236
|
|
|
286
|
-
// Update profile
|
|
287
|
-
await sso.user.updateProfile({ email: 'newemail@example.com' });
|
|
288
|
-
|
|
289
|
-
// Get subscription
|
|
290
|
-
const subscription = await sso.user.getSubscription();
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### Social Account Identities
|
|
294
|
-
|
|
295
|
-
Manage linked social accounts for the authenticated user.
|
|
296
|
-
|
|
297
|
-
```typescript
|
|
298
|
-
// List all linked social accounts
|
|
299
|
-
const identities = await sso.user.identities.list();
|
|
300
|
-
|
|
301
237
|
// Start linking a new social account
|
|
302
|
-
const { authorization_url } = await sso.user.identities.startLink('
|
|
238
|
+
const { authorization_url } = await sso.user.identities.startLink('google');
|
|
303
239
|
window.location.href = authorization_url;
|
|
304
240
|
|
|
305
241
|
// Unlink a social account
|
|
306
|
-
await sso.user.identities.unlink('
|
|
242
|
+
await sso.user.identities.unlink('github');
|
|
307
243
|
```
|
|
308
244
|
|
|
309
|
-
###
|
|
245
|
+
### Invitations (`sso.invitations`)
|
|
246
|
+
|
|
247
|
+
Manages team invitations for an organization.
|
|
310
248
|
|
|
311
249
|
```typescript
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
250
|
+
// Create and send an invitation
|
|
251
|
+
await sso.invitations.create('acme-corp', {
|
|
252
|
+
email: 'new-dev@example.com',
|
|
253
|
+
role: 'member'
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// List invitations for the current user
|
|
257
|
+
const myInvites = await sso.invitations.listForUser();
|
|
315
258
|
```
|
|
316
259
|
|
|
317
|
-
### Platform Administration
|
|
260
|
+
### Platform Administration (`sso.platform`)
|
|
318
261
|
|
|
319
262
|
Platform owner methods require a Platform Owner JWT.
|
|
320
263
|
|
|
321
264
|
```typescript
|
|
322
|
-
// List all organizations
|
|
323
|
-
const
|
|
324
|
-
status: 'pending'
|
|
325
|
-
page: 1,
|
|
326
|
-
limit: 50
|
|
265
|
+
// List all organizations awaiting approval
|
|
266
|
+
const pendingOrgs = await sso.platform.organizations.list({
|
|
267
|
+
status: 'pending'
|
|
327
268
|
});
|
|
328
269
|
|
|
329
|
-
// Approve organization
|
|
330
|
-
await sso.platform.organizations.approve('org-id', {
|
|
270
|
+
// Approve an organization
|
|
271
|
+
await sso.platform.organizations.approve('org-id-123', {
|
|
331
272
|
tier_id: 'tier-starter'
|
|
332
273
|
});
|
|
274
|
+
```
|
|
333
275
|
|
|
334
|
-
|
|
335
|
-
await sso.platform.organizations.reject('org-id', {
|
|
336
|
-
reason: 'Does not meet requirements'
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
// Suspend/activate
|
|
340
|
-
await sso.platform.organizations.suspend('org-id');
|
|
341
|
-
await sso.platform.organizations.activate('org-id');
|
|
342
|
-
|
|
343
|
-
// Update tier
|
|
344
|
-
await sso.platform.organizations.updateTier('org-id', {
|
|
345
|
-
tier_id: 'tier-pro',
|
|
346
|
-
max_services: 20
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
// Promote platform owner
|
|
350
|
-
await sso.platform.promoteOwner({
|
|
351
|
-
user_id: 'user-uuid-here'
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
// Demote platform owner to regular user
|
|
355
|
-
await sso.platform.demoteOwner('user-uuid-here');
|
|
276
|
+
#### Platform Analytics (`sso.platform.analytics`)
|
|
356
277
|
|
|
357
|
-
|
|
358
|
-
const tiers = await sso.platform.getTiers();
|
|
278
|
+
Provides platform-wide metrics for platform owners.
|
|
359
279
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
});
|
|
280
|
+
```typescript
|
|
281
|
+
// Get platform-wide analytics overview
|
|
282
|
+
const overview = await sso.platform.analytics.getOverview();
|
|
283
|
+
console.log(`Total Users: ${overview.total_users}`);
|
|
365
284
|
```
|
|
366
285
|
|
|
367
286
|
## Error Handling
|
|
@@ -377,98 +296,17 @@ try {
|
|
|
377
296
|
if (error instanceof SsoApiError) {
|
|
378
297
|
console.error(`Error ${error.statusCode}: ${error.message}`);
|
|
379
298
|
console.error(`Code: ${error.errorCode}`);
|
|
380
|
-
console.error(`Timestamp: ${error.timestamp}`);
|
|
381
299
|
|
|
382
|
-
// Utility methods
|
|
383
300
|
if (error.isAuthError()) {
|
|
384
301
|
// Redirect to login
|
|
385
302
|
}
|
|
386
|
-
if (error.isNotFound()) {
|
|
387
|
-
// Show 404 page
|
|
388
|
-
}
|
|
389
|
-
if (error.is('SERVICE_LIMIT_EXCEEDED')) {
|
|
390
|
-
// Handle specific error
|
|
391
|
-
}
|
|
392
|
-
if (error.isForbidden()) {
|
|
393
|
-
// Handle permission errors
|
|
394
|
-
}
|
|
395
|
-
if (error.isAuthError()) {
|
|
396
|
-
// Handle authentication errors
|
|
397
|
-
}
|
|
398
303
|
}
|
|
399
304
|
}
|
|
400
305
|
```
|
|
401
306
|
|
|
402
|
-
## Framework Integration Examples
|
|
403
|
-
|
|
404
|
-
### Vue 3 + Pinia
|
|
405
|
-
|
|
406
|
-
```typescript
|
|
407
|
-
// stores/auth.ts
|
|
408
|
-
import { defineStore } from 'pinia';
|
|
409
|
-
import { SsoClient } from '@drmhse/sso-sdk';
|
|
410
|
-
|
|
411
|
-
export const useAuthStore = defineStore('auth', {
|
|
412
|
-
state: () => ({
|
|
413
|
-
token: localStorage.getItem('jwt'),
|
|
414
|
-
user: null
|
|
415
|
-
}),
|
|
416
|
-
|
|
417
|
-
actions: {
|
|
418
|
-
async login(token: string) {
|
|
419
|
-
this.token = token;
|
|
420
|
-
localStorage.setItem('jwt', token);
|
|
421
|
-
sso.setAuthToken(token);
|
|
422
|
-
await this.fetchUser();
|
|
423
|
-
},
|
|
424
|
-
|
|
425
|
-
async logout() {
|
|
426
|
-
await sso.auth.logout();
|
|
427
|
-
this.token = null;
|
|
428
|
-
this.user = null;
|
|
429
|
-
localStorage.removeItem('jwt');
|
|
430
|
-
sso.setAuthToken(null);
|
|
431
|
-
},
|
|
432
|
-
|
|
433
|
-
async fetchUser() {
|
|
434
|
-
this.user = await sso.user.getProfile();
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
// Global SSO instance
|
|
440
|
-
export const sso = new SsoClient({
|
|
441
|
-
baseURL: import.meta.env.VITE_SSO_URL,
|
|
442
|
-
token: localStorage.getItem('jwt')
|
|
443
|
-
});
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
### React + Context
|
|
447
|
-
|
|
448
|
-
```typescript
|
|
449
|
-
// SsoContext.tsx
|
|
450
|
-
import { createContext, useContext } from 'react';
|
|
451
|
-
import { SsoClient } from '@drmhse/sso-sdk';
|
|
452
|
-
|
|
453
|
-
const sso = new SsoClient({
|
|
454
|
-
baseURL: process.env.REACT_APP_SSO_URL,
|
|
455
|
-
token: localStorage.getItem('jwt')
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
const SsoContext = createContext(sso);
|
|
459
|
-
|
|
460
|
-
export const useSso = () => useContext(SsoContext);
|
|
461
|
-
|
|
462
|
-
export const SsoProvider = ({ children }) => (
|
|
463
|
-
<SsoContext.Provider value={sso}>
|
|
464
|
-
{children}
|
|
465
|
-
</SsoContext.Provider>
|
|
466
|
-
);
|
|
467
|
-
```
|
|
468
|
-
|
|
469
307
|
## TypeScript
|
|
470
308
|
|
|
471
|
-
The SDK is written in TypeScript and includes complete type definitions.
|
|
309
|
+
The SDK is written in TypeScript and includes complete type definitions.
|
|
472
310
|
|
|
473
311
|
```typescript
|
|
474
312
|
import type {
|
|
@@ -476,30 +314,11 @@ import type {
|
|
|
476
314
|
Service,
|
|
477
315
|
User,
|
|
478
316
|
JwtClaims,
|
|
479
|
-
OAuthProvider,
|
|
480
|
-
SsoClientOptions,
|
|
481
317
|
SsoApiError,
|
|
482
|
-
AnalyticsQuery,
|
|
483
|
-
LoginTrendPoint,
|
|
484
|
-
LoginsByService,
|
|
485
|
-
LoginsByProvider,
|
|
486
|
-
RecentLogin,
|
|
487
|
-
Invitation,
|
|
488
|
-
Subscription,
|
|
489
|
-
ProviderToken,
|
|
490
|
-
UserProfile,
|
|
491
|
-
PlatformOrganizationResponse,
|
|
492
|
-
AuditLogEntry,
|
|
493
318
|
// ... and many more types
|
|
494
319
|
} from '@drmhse/sso-sdk';
|
|
495
320
|
```
|
|
496
321
|
|
|
497
|
-
All API responses, request payloads, and configuration options are fully typed for excellent IDE support and compile-time safety.
|
|
498
|
-
|
|
499
322
|
## License
|
|
500
323
|
|
|
501
324
|
MIT
|
|
502
|
-
|
|
503
|
-
## Contributing
|
|
504
|
-
|
|
505
|
-
Contributions are welcome! Please open an issue or pull request.
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED