@deliverart/sdk-js-authentication 2.1.50 → 2.1.52

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 (2) hide show
  1. package/README.md +373 -0
  2. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,373 @@
1
+ # @deliverart/sdk-js-authentication
2
+
3
+ Authentication plugin for the DeliverArt JavaScript SDK. Automatically adds Bearer token authentication to all API requests.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @deliverart/sdk-js-authentication @deliverart/sdk-js-core
9
+ # or
10
+ pnpm add @deliverart/sdk-js-authentication @deliverart/sdk-js-core
11
+ # or
12
+ yarn add @deliverart/sdk-js-authentication @deliverart/sdk-js-core
13
+ ```
14
+
15
+ ## Exported Types
16
+
17
+ ### AuthenticationPlugin
18
+ ```typescript
19
+ class AuthenticationPlugin implements ApiClientPlugin<AuthenticationExtension>
20
+ ```
21
+ Plugin that adds JWT Bearer token authentication to all API requests.
22
+
23
+ **Constructor:**
24
+ - `constructor(config: AuthenticationConfig)`
25
+
26
+ ### AuthenticationConfig
27
+ ```typescript
28
+ interface AuthenticationConfig {
29
+ getAccessToken: () => Promise<string | null>
30
+ }
31
+ ```
32
+ Configuration object for the authentication plugin.
33
+
34
+ **Properties:**
35
+ - `getAccessToken: () => Promise<string | null>` (required) - Async function that returns the access token or null if not authenticated
36
+
37
+ ### AuthenticationExtension
38
+ ```typescript
39
+ interface AuthenticationExtension extends ApiExtension {
40
+ authentication: {
41
+ enable: () => void;
42
+ disable: () => void;
43
+ }
44
+ }
45
+ ```
46
+ Extension added to the API client when the plugin is installed.
47
+
48
+ **Methods:**
49
+ - `enable()` - Enable authentication (adds Authorization header to requests)
50
+ - `disable()` - Disable authentication (skips adding Authorization header)
51
+
52
+ ### Errors
53
+
54
+ #### AuthenticationError
55
+ ```typescript
56
+ class AuthenticationError extends Error
57
+ ```
58
+ Thrown when authentication is required but no access token is available.
59
+
60
+ ## Usage
61
+
62
+ ### Basic Setup
63
+
64
+ ```typescript
65
+ import { createApiClient } from '@deliverart/sdk-js-core';
66
+ import { AuthenticationPlugin } from '@deliverart/sdk-js-authentication';
67
+
68
+ const getAccessToken = async (): Promise<string | null> => {
69
+ // Retrieve token from your storage
70
+ return localStorage.getItem('accessToken');
71
+ };
72
+
73
+ const client = createApiClient({
74
+ baseUrl: 'https://api.deliverart.com'
75
+ })
76
+ .addPlugin(new AuthenticationPlugin({ getAccessToken }));
77
+ ```
78
+
79
+ **Parameters:**
80
+ - `getAccessToken` (required) - Function that retrieves the current access token
81
+
82
+ ### With Different Token Storage
83
+
84
+ #### LocalStorage
85
+ ```typescript
86
+ const getAccessToken = async (): Promise<string | null> => {
87
+ return localStorage.getItem('accessToken');
88
+ };
89
+ ```
90
+
91
+ #### SessionStorage
92
+ ```typescript
93
+ const getAccessToken = async (): Promise<string | null> => {
94
+ return sessionStorage.getItem('accessToken');
95
+ };
96
+ ```
97
+
98
+ #### Cookies
99
+ ```typescript
100
+ import Cookies from 'js-cookie';
101
+
102
+ const getAccessToken = async (): Promise<string | null> => {
103
+ return Cookies.get('accessToken') ?? null;
104
+ };
105
+ ```
106
+
107
+ #### Next.js with Server Actions
108
+ ```typescript
109
+ import { cookies } from 'next/headers';
110
+
111
+ const getAccessToken = async (): Promise<string | null> => {
112
+ const cookieStore = await cookies();
113
+ return cookieStore.get('accessToken')?.value ?? null;
114
+ };
115
+ ```
116
+
117
+ #### Auth Provider (e.g., Auth0, Clerk)
118
+ ```typescript
119
+ import { useAuth } from '@clerk/nextjs';
120
+
121
+ const getAccessToken = async (): Promise<string | null> => {
122
+ const { getToken } = useAuth();
123
+ return await getToken();
124
+ };
125
+ ```
126
+
127
+ ### Enabling/Disabling Authentication
128
+
129
+ ```typescript
130
+ // Disable authentication temporarily
131
+ client.authentication.disable();
132
+
133
+ // Make unauthenticated requests
134
+ await client.call(new PublicRequest());
135
+
136
+ // Re-enable authentication
137
+ client.authentication.enable();
138
+
139
+ // Make authenticated requests
140
+ await client.call(new ProtectedRequest());
141
+ ```
142
+
143
+ **Use Cases:**
144
+ - Public endpoints that don't require authentication
145
+ - Guest checkout flows
146
+ - Login/registration requests
147
+
148
+ ### Complete Example with Next.js
149
+
150
+ ```typescript
151
+ // lib/sdk/client.ts
152
+ import { createApiClient, type ApiClient } from '@deliverart/sdk-js-core';
153
+ import { AuthenticationPlugin } from '@deliverart/sdk-js-authentication';
154
+ import { ErrorHandlerPlugin } from '@deliverart/sdk-js-error-handler';
155
+
156
+ const getAccessToken = async (): Promise<string | null> => {
157
+ // Server-side: get from cookies
158
+ if (typeof window === 'undefined') {
159
+ const { cookies } = await import('next/headers');
160
+ const cookieStore = await cookies();
161
+ return cookieStore.get('accessToken')?.value ?? null;
162
+ }
163
+
164
+ // Client-side: get from localStorage
165
+ return localStorage.getItem('accessToken');
166
+ };
167
+
168
+ export const sdk = createApiClient({
169
+ baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL!
170
+ })
171
+ .addPlugin(new ErrorHandlerPlugin())
172
+ .addPlugin(new AuthenticationPlugin({ getAccessToken }));
173
+ ```
174
+
175
+ ### Login Flow Example
176
+
177
+ ```typescript
178
+ import { sdk } from './lib/sdk/client';
179
+ import { Login } from '@deliverart/sdk-js-auth';
180
+
181
+ // Disable authentication for login request
182
+ sdk.authentication.disable();
183
+
184
+ try {
185
+ const response = await sdk.call(new Login({
186
+ email: 'user@example.com',
187
+ password: 'password123'
188
+ }));
189
+
190
+ // Store the token
191
+ localStorage.setItem('accessToken', response.token);
192
+
193
+ // Re-enable authentication for subsequent requests
194
+ sdk.authentication.enable();
195
+
196
+ // Now all requests will include the Authorization header
197
+ const user = await sdk.call(new GetCurrentUser());
198
+
199
+ } catch (error) {
200
+ console.error('Login failed:', error);
201
+ }
202
+ ```
203
+
204
+ ### Logout Flow Example
205
+
206
+ ```typescript
207
+ import { sdk } from './lib/sdk/client';
208
+
209
+ // Clear the token
210
+ localStorage.removeItem('accessToken');
211
+
212
+ // Disable authentication (optional, depends on your needs)
213
+ sdk.authentication.disable();
214
+
215
+ // Redirect to login page
216
+ window.location.href = '/login';
217
+ ```
218
+
219
+ ### Token Refresh Example
220
+
221
+ ```typescript
222
+ import { sdk } from './lib/sdk/client';
223
+ import { AuthenticationError } from '@deliverart/sdk-js-authentication';
224
+
225
+ let tokenRefreshPromise: Promise<string> | null = null;
226
+
227
+ const getAccessToken = async (): Promise<string | null> => {
228
+ let token = localStorage.getItem('accessToken');
229
+
230
+ // Check if token is expired (you need to implement this)
231
+ if (token && isTokenExpired(token)) {
232
+ // Ensure only one refresh happens at a time
233
+ if (!tokenRefreshPromise) {
234
+ tokenRefreshPromise = refreshToken();
235
+ }
236
+
237
+ try {
238
+ token = await tokenRefreshPromise;
239
+ localStorage.setItem('accessToken', token);
240
+ } finally {
241
+ tokenRefreshPromise = null;
242
+ }
243
+ }
244
+
245
+ return token;
246
+ };
247
+
248
+ async function refreshToken(): Promise<string> {
249
+ const refreshToken = localStorage.getItem('refreshToken');
250
+
251
+ if (!refreshToken) {
252
+ throw new AuthenticationError('No refresh token available');
253
+ }
254
+
255
+ // Disable authentication for refresh request
256
+ sdk.authentication.disable();
257
+
258
+ try {
259
+ const response = await sdk.call(new RefreshToken({ refreshToken }));
260
+ sdk.authentication.enable();
261
+ return response.accessToken;
262
+ } catch (error) {
263
+ // Refresh failed, redirect to login
264
+ localStorage.clear();
265
+ window.location.href = '/login';
266
+ throw error;
267
+ }
268
+ }
269
+
270
+ function isTokenExpired(token: string): boolean {
271
+ try {
272
+ const payload = JSON.parse(atob(token.split('.')[1]));
273
+ return payload.exp * 1000 < Date.now();
274
+ } catch {
275
+ return true;
276
+ }
277
+ }
278
+ ```
279
+
280
+ ### Error Handling
281
+
282
+ ```typescript
283
+ import { AuthenticationError } from '@deliverart/sdk-js-authentication';
284
+
285
+ try {
286
+ await sdk.call(new GetUser('123'));
287
+ } catch (error) {
288
+ if (error instanceof AuthenticationError) {
289
+ console.error('Authentication failed:', error.message);
290
+ // Redirect to login page
291
+ window.location.href = '/login';
292
+ }
293
+ }
294
+ ```
295
+
296
+ ## How It Works
297
+
298
+ The plugin adds a request middleware that:
299
+
300
+ 1. Calls your `getAccessToken` function to retrieve the current token
301
+ 2. If a token is found, adds it to the `Authorization` header as `Bearer <token>`
302
+ 3. If no token is found and authentication is enabled, throws an `AuthenticationError`
303
+ 4. If authentication is disabled, skips adding the Authorization header
304
+
305
+ ## Best Practices
306
+
307
+ ### 1. Centralized Token Management
308
+ Create a dedicated module for token management:
309
+
310
+ ```typescript
311
+ // lib/auth/tokens.ts
312
+ export const setAccessToken = (token: string) => {
313
+ localStorage.setItem('accessToken', token);
314
+ };
315
+
316
+ export const getAccessToken = (): string | null => {
317
+ return localStorage.getItem('accessToken');
318
+ };
319
+
320
+ export const clearTokens = () => {
321
+ localStorage.removeItem('accessToken');
322
+ localStorage.removeItem('refreshToken');
323
+ };
324
+ ```
325
+
326
+ ### 2. Secure Token Storage
327
+ - Use `httpOnly` cookies for tokens when possible (more secure)
328
+ - Avoid storing sensitive tokens in localStorage on production if possible
329
+ - Consider using secure storage libraries for mobile apps
330
+
331
+ ### 3. Handle Token Expiration
332
+ Implement automatic token refresh before the token expires:
333
+
334
+ ```typescript
335
+ const getAccessToken = async (): Promise<string | null> => {
336
+ const token = localStorage.getItem('accessToken');
337
+
338
+ if (token && willExpireSoon(token)) {
339
+ return await refreshAccessToken();
340
+ }
341
+
342
+ return token;
343
+ };
344
+
345
+ function willExpireSoon(token: string, bufferSeconds = 60): boolean {
346
+ try {
347
+ const payload = JSON.parse(atob(token.split('.')[1]));
348
+ return payload.exp * 1000 < Date.now() + (bufferSeconds * 1000);
349
+ } catch {
350
+ return true;
351
+ }
352
+ }
353
+ ```
354
+
355
+ ### 4. Global Error Handling
356
+ Set up global error handling for authentication errors:
357
+
358
+ ```typescript
359
+ import { ApiError } from '@deliverart/sdk-js-error-handler';
360
+
361
+ window.addEventListener('unhandledrejection', (event) => {
362
+ if (event.reason instanceof ApiError && event.reason.statusCode === 401) {
363
+ // Handle unauthorized errors globally
364
+ clearTokens();
365
+ window.location.href = '/login';
366
+ }
367
+ });
368
+ ```
369
+
370
+ ## License
371
+
372
+ MIT
373
+
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deliverart/sdk-js-authentication",
3
3
  "description": "Authentication module for DeliverArt SDK",
4
- "version": "2.1.50",
4
+ "version": "2.1.52",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "dist"
19
19
  ],
20
20
  "dependencies": {
21
- "@deliverart/sdk-js-core": "2.1.50"
21
+ "@deliverart/sdk-js-core": "2.1.52"
22
22
  },
23
23
  "publishConfig": {
24
24
  "access": "public"