tenneo-auth-plugin 0.1.0 → 0.1.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 +234 -386
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,214 +1,76 @@
|
|
|
1
|
-
#
|
|
1
|
+
# tenneo-auth-plugin
|
|
2
2
|
|
|
3
|
-
Production-ready
|
|
3
|
+
Production-ready React authentication plugin with OAuth 2.0 PKCE support for enterprise applications.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/tenneo-auth-plugin)
|
|
6
|
+
[](https://www.npmjs.com/package/tenneo-auth-plugin)
|
|
7
|
+
[](https://www.npmjs.com/package/tenneo-auth-plugin)
|
|
6
8
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
- Full OAuth 2.0 PKCE flow implementation
|
|
10
|
-
- Multi-tenant support via tenant code resolution
|
|
11
|
-
- Automatic token refresh
|
|
12
|
-
- Session-based storage with namespacing
|
|
13
|
-
- React hooks and Context API integration
|
|
14
|
-
- TypeScript with strict typing
|
|
15
|
-
- Configurable storage adapters (session, cookie, memory)
|
|
16
|
-
- Auth engine architecture for advanced use cases
|
|
17
|
-
- Protected route component
|
|
18
|
-
- Callback handling component
|
|
19
|
-
|
|
20
|
-
## Installation
|
|
21
|
-
|
|
22
|
-
### Installation from npm registry (stable)
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npm install @tenneo/auth-plugin
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Installation from npm registry (beta)
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install @tenneo/auth-plugin@beta
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Installation from hosted .tgz file (without pack)
|
|
35
|
-
|
|
36
|
-
If the plugin is hosted on a server as a `.tgz` file, install directly from the URL:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npm install https://your-server.com/path/tenneo-auth-plugin-0.1.0-beta.1.tgz
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Or add it to your `package.json`:
|
|
43
|
-
|
|
44
|
-
```json
|
|
45
|
-
{
|
|
46
|
-
"dependencies": {
|
|
47
|
-
"@tenneo/auth-plugin": "https://your-server.com/path/tenneo-auth-plugin-0.1.0-beta.1.tgz"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Then run:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npm install
|
|
56
|
-
```
|
|
9
|
+
## Overview
|
|
57
10
|
|
|
58
|
-
|
|
11
|
+
tenneo-auth-plugin is a comprehensive authentication solution designed for modern React applications. It implements the OAuth 2.0 Authorization Code flow with PKCE (Proof Key for Code Exchange), providing secure authentication without exposing client secrets in browser-based applications.
|
|
59
12
|
|
|
60
|
-
|
|
13
|
+
The plugin features a robust multi-tenant architecture that automatically resolves tenant configuration based on tenant codes. This makes it ideal for SaaS platforms and enterprise applications where multiple tenants share the same codebase but require isolated authentication contexts.
|
|
61
14
|
|
|
62
|
-
|
|
15
|
+
Built with TypeScript and following clean architecture principles, the plugin handles the complete token lifecycle including automatic refresh, secure storage, and session management. The React Context API integration provides a seamless developer experience with hooks-based access to authentication state and methods.
|
|
63
16
|
|
|
64
|
-
|
|
65
|
-
cd tenneo-auth-plugin
|
|
66
|
-
npm install
|
|
67
|
-
npm run build
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**Step 2: Create the package**
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
npm pack
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
This creates a file like `tenneo-auth-plugin-0.1.0-beta.1.tgz` in the current directory.
|
|
77
|
-
|
|
78
|
-
**Step 3: Install in your application**
|
|
79
|
-
|
|
80
|
-
Copy the `.tgz` file to your application directory and install:
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
npm install ./tenneo-auth-plugin-0.1.0-beta.1.tgz
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Or specify the full path:
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
npm install /path/to/tenneo-auth-plugin-0.1.0-beta.1.tgz
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Installation with local source (development)
|
|
93
|
-
|
|
94
|
-
Use this method during development to link the plugin directly without packing:
|
|
95
|
-
|
|
96
|
-
**Method 1: npm link (recommended for development)**
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
# In the plugin directory
|
|
100
|
-
cd tenneo-auth-plugin
|
|
101
|
-
npm install
|
|
102
|
-
npm run build
|
|
103
|
-
npm link
|
|
104
|
-
|
|
105
|
-
# In your application directory
|
|
106
|
-
cd your-application
|
|
107
|
-
npm link @tenneo/auth-plugin
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
To unlink when done:
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
# In your application directory
|
|
114
|
-
npm unlink @tenneo/auth-plugin
|
|
115
|
-
|
|
116
|
-
# In the plugin directory
|
|
117
|
-
npm unlink
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
**Method 2: File path in package.json**
|
|
121
|
-
|
|
122
|
-
Add the local path to your application's `package.json`:
|
|
123
|
-
|
|
124
|
-
```json
|
|
125
|
-
{
|
|
126
|
-
"dependencies": {
|
|
127
|
-
"@tenneo/auth-plugin": "file:../tenneo-auth-plugin"
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Then run:
|
|
17
|
+
## Installation
|
|
133
18
|
|
|
134
19
|
```bash
|
|
135
|
-
npm install
|
|
20
|
+
npm install tenneo-auth-plugin
|
|
136
21
|
```
|
|
137
22
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
```bash
|
|
141
|
-
npm install ../tenneo-auth-plugin
|
|
142
|
-
```
|
|
23
|
+
### Requirements
|
|
143
24
|
|
|
144
|
-
|
|
25
|
+
- React 18 or higher
|
|
26
|
+
- React DOM 18 or higher
|
|
27
|
+
- React Router (recommended for callback handling)
|
|
145
28
|
|
|
146
29
|
## Quick Start
|
|
147
30
|
|
|
148
|
-
### 1. Wrap your
|
|
149
|
-
|
|
150
|
-
**Basic Usage:**
|
|
31
|
+
### 1. Wrap your application with AuthProvider
|
|
151
32
|
|
|
152
33
|
```tsx
|
|
153
|
-
import { AuthProvider } from '
|
|
34
|
+
import { AuthProvider } from 'tenneo-auth-plugin';
|
|
154
35
|
|
|
155
36
|
function App() {
|
|
156
37
|
return (
|
|
157
38
|
<AuthProvider tenantCode="your-tenant-code">
|
|
158
|
-
<
|
|
159
|
-
</AuthProvider>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
**With App ID (for storage namespacing):**
|
|
165
|
-
|
|
166
|
-
```tsx
|
|
167
|
-
import { AuthProvider } from '@tenneo/auth-plugin';
|
|
168
|
-
|
|
169
|
-
function App() {
|
|
170
|
-
return (
|
|
171
|
-
<AuthProvider
|
|
172
|
-
tenantCode="your-tenant-code"
|
|
173
|
-
appId="my-app"
|
|
174
|
-
>
|
|
175
|
-
<YourApp />
|
|
39
|
+
<YourApplication />
|
|
176
40
|
</AuthProvider>
|
|
177
41
|
);
|
|
178
42
|
}
|
|
179
43
|
```
|
|
180
44
|
|
|
181
|
-
### 2.
|
|
45
|
+
### 2. Access authentication state with useAuth
|
|
182
46
|
|
|
183
47
|
```tsx
|
|
184
|
-
import { useAuth } from '
|
|
48
|
+
import { useAuth } from 'tenneo-auth-plugin';
|
|
185
49
|
|
|
186
|
-
function
|
|
187
|
-
const { isAuthenticated,
|
|
50
|
+
function Dashboard() {
|
|
51
|
+
const { isAuthenticated, isLoading, accessToken, logout } = useAuth();
|
|
188
52
|
|
|
189
53
|
if (isLoading) {
|
|
190
54
|
return <div>Loading...</div>;
|
|
191
55
|
}
|
|
192
56
|
|
|
193
57
|
if (!isAuthenticated) {
|
|
194
|
-
return <div>
|
|
58
|
+
return <div>Please log in to continue.</div>;
|
|
195
59
|
}
|
|
196
60
|
|
|
197
61
|
return (
|
|
198
62
|
<div>
|
|
199
|
-
<
|
|
200
|
-
<button onClick={logout}>
|
|
63
|
+
<h1>Welcome to Dashboard</h1>
|
|
64
|
+
<button onClick={logout}>Sign Out</button>
|
|
201
65
|
</div>
|
|
202
66
|
);
|
|
203
67
|
}
|
|
204
68
|
```
|
|
205
69
|
|
|
206
|
-
### 3.
|
|
207
|
-
|
|
208
|
-
Add the `AuthCallback` component to handle OAuth redirects:
|
|
70
|
+
### 3. Handle OAuth callback
|
|
209
71
|
|
|
210
72
|
```tsx
|
|
211
|
-
import { AuthCallback } from '
|
|
73
|
+
import { AuthCallback } from 'tenneo-auth-plugin';
|
|
212
74
|
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
|
213
75
|
|
|
214
76
|
function App() {
|
|
@@ -216,9 +78,16 @@ function App() {
|
|
|
216
78
|
<AuthProvider tenantCode="your-tenant-code">
|
|
217
79
|
<BrowserRouter>
|
|
218
80
|
<Routes>
|
|
219
|
-
<Route
|
|
81
|
+
<Route
|
|
82
|
+
path="/callback"
|
|
83
|
+
element={
|
|
84
|
+
<AuthCallback
|
|
85
|
+
successPath="/dashboard"
|
|
86
|
+
loginPath="/login"
|
|
87
|
+
/>
|
|
88
|
+
}
|
|
89
|
+
/>
|
|
220
90
|
<Route path="/dashboard" element={<Dashboard />} />
|
|
221
|
-
{/* ... other routes */}
|
|
222
91
|
</Routes>
|
|
223
92
|
</BrowserRouter>
|
|
224
93
|
</AuthProvider>
|
|
@@ -226,10 +95,10 @@ function App() {
|
|
|
226
95
|
}
|
|
227
96
|
```
|
|
228
97
|
|
|
229
|
-
### 4. Protect routes
|
|
98
|
+
### 4. Protect routes
|
|
230
99
|
|
|
231
100
|
```tsx
|
|
232
|
-
import { ProtectedRoute } from '
|
|
101
|
+
import { ProtectedRoute } from 'tenneo-auth-plugin';
|
|
233
102
|
|
|
234
103
|
function App() {
|
|
235
104
|
return (
|
|
@@ -240,7 +109,7 @@ function App() {
|
|
|
240
109
|
<Route
|
|
241
110
|
path="/dashboard"
|
|
242
111
|
element={
|
|
243
|
-
<ProtectedRoute fallback={<div>
|
|
112
|
+
<ProtectedRoute fallback={<div>Authenticating...</div>}>
|
|
244
113
|
<Dashboard />
|
|
245
114
|
</ProtectedRoute>
|
|
246
115
|
}
|
|
@@ -252,305 +121,298 @@ function App() {
|
|
|
252
121
|
}
|
|
253
122
|
```
|
|
254
123
|
|
|
255
|
-
##
|
|
124
|
+
## Features
|
|
256
125
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
126
|
+
- OAuth 2.0 PKCE flow for secure browser-based authentication
|
|
127
|
+
- Automatic token refresh before expiration
|
|
128
|
+
- Multi-tenant support with automatic tenant resolution
|
|
129
|
+
- Pluggable storage adapters (session, cookie, memory)
|
|
130
|
+
- Authentication event system for observability
|
|
131
|
+
- Strict TypeScript definitions throughout
|
|
132
|
+
- Runtime configuration override support
|
|
133
|
+
- Window-based configuration injection
|
|
134
|
+
- Clean layered architecture
|
|
135
|
+
- Tree-shakeable ESM and CJS builds
|
|
136
|
+
- React 18+ compatibility
|
|
263
137
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
1. **Props** - Values passed to `AuthProvider`
|
|
267
|
-
2. **Window config** - `window.__AUTH_CONFIG__` or `window.__APP_CONFIG__`
|
|
268
|
-
3. **Environment variables** - `VITE_*` prefixed variables
|
|
269
|
-
4. **Defaults** - Built-in fallback values
|
|
138
|
+
## AuthProvider Props
|
|
270
139
|
|
|
271
|
-
|
|
140
|
+
| Prop | Type | Required | Default | Description |
|
|
141
|
+
|------|------|----------|---------|-------------|
|
|
142
|
+
| `tenantCode` | `string` | No | - | Tenant code for configuration resolution |
|
|
143
|
+
| `appId` | `string` | No | `''` | Application identifier for storage namespacing |
|
|
144
|
+
| `autoInit` | `boolean` | No | `true` | Automatically initialize authentication on mount |
|
|
145
|
+
| `storageAdapter` | `StorageAdapter` | No | `null` | Custom storage adapter instance |
|
|
272
146
|
|
|
273
|
-
|
|
147
|
+
## Hooks API
|
|
274
148
|
|
|
275
|
-
|
|
149
|
+
### useAuth()
|
|
276
150
|
|
|
277
|
-
|
|
151
|
+
Primary hook for accessing authentication state and methods.
|
|
278
152
|
|
|
279
153
|
```tsx
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
154
|
+
import { useAuth } from 'tenneo-auth-plugin';
|
|
155
|
+
|
|
156
|
+
function Component() {
|
|
157
|
+
const {
|
|
158
|
+
isAuthenticated, // boolean - Current authentication status
|
|
159
|
+
accessToken, // string | null - Current access token
|
|
160
|
+
isLoading, // boolean - Loading state during auth operations
|
|
161
|
+
error, // string | null - Error message if any
|
|
162
|
+
login, // () => Promise<void> - Trigger login flow
|
|
163
|
+
logout, // () => Promise<void> - Sign out and clear session
|
|
164
|
+
refreshToken, // () => Promise<string> - Manually refresh token
|
|
165
|
+
getAccessToken, // () => Promise<string> - Get valid token (auto-refresh)
|
|
166
|
+
} = useAuth();
|
|
167
|
+
}
|
|
290
168
|
```
|
|
291
169
|
|
|
292
|
-
|
|
170
|
+
### useAuthInit()
|
|
293
171
|
|
|
294
|
-
|
|
172
|
+
Hook for manual authentication initialization.
|
|
295
173
|
|
|
296
174
|
```tsx
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
175
|
+
import { useAuthInit } from 'tenneo-auth-plugin';
|
|
176
|
+
|
|
177
|
+
function Component() {
|
|
178
|
+
const {
|
|
179
|
+
isLoading, // boolean - Initialization in progress
|
|
180
|
+
error, // string | null - Initialization error
|
|
181
|
+
init, // () => Promise<void> - Trigger initialization
|
|
182
|
+
} = useAuthInit();
|
|
183
|
+
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
init();
|
|
186
|
+
}, [init]);
|
|
187
|
+
}
|
|
301
188
|
```
|
|
302
189
|
|
|
303
|
-
|
|
190
|
+
## Components
|
|
304
191
|
|
|
305
|
-
|
|
192
|
+
### AuthCallback
|
|
306
193
|
|
|
307
|
-
Handles OAuth callback and token exchange
|
|
194
|
+
Handles OAuth authorization callback and token exchange.
|
|
308
195
|
|
|
309
196
|
```tsx
|
|
197
|
+
import { AuthCallback } from 'tenneo-auth-plugin';
|
|
198
|
+
|
|
310
199
|
<AuthCallback
|
|
311
|
-
loginPath="/login"
|
|
312
|
-
successPath="/dashboard" // Redirect
|
|
313
|
-
homePath="/"
|
|
200
|
+
loginPath="/login" // Redirect on error (default: '/login')
|
|
201
|
+
successPath="/dashboard" // Redirect on success (default: '/dashboard')
|
|
202
|
+
homePath="/" // Fallback path (default: '/')
|
|
314
203
|
/>
|
|
315
204
|
```
|
|
316
205
|
|
|
317
|
-
|
|
206
|
+
### ProtectedRoute
|
|
318
207
|
|
|
319
|
-
|
|
208
|
+
Wrapper component that ensures authentication before rendering children.
|
|
320
209
|
|
|
321
210
|
```tsx
|
|
211
|
+
import { ProtectedRoute } from 'tenneo-auth-plugin';
|
|
212
|
+
|
|
322
213
|
<ProtectedRoute
|
|
323
|
-
fallback={<
|
|
324
|
-
autoLogin={true}
|
|
214
|
+
fallback={<LoadingSpinner />} // Shown while checking auth
|
|
215
|
+
autoLogin={true} // Auto-redirect to login (default: true)
|
|
325
216
|
>
|
|
326
217
|
<ProtectedContent />
|
|
327
218
|
</ProtectedRoute>
|
|
328
219
|
```
|
|
329
220
|
|
|
330
|
-
|
|
221
|
+
## Core API
|
|
331
222
|
|
|
332
|
-
|
|
223
|
+
### bootstrap()
|
|
333
224
|
|
|
334
|
-
Initializes authentication flow
|
|
225
|
+
Initializes the authentication flow. Called automatically by AuthProvider when `autoInit` is true.
|
|
335
226
|
|
|
336
227
|
```tsx
|
|
337
|
-
import { bootstrap } from '
|
|
228
|
+
import { bootstrap } from 'tenneo-auth-plugin';
|
|
229
|
+
|
|
338
230
|
await bootstrap();
|
|
339
231
|
```
|
|
340
232
|
|
|
341
|
-
|
|
233
|
+
### getAccessToken()
|
|
342
234
|
|
|
343
|
-
|
|
235
|
+
Retrieves a valid access token, automatically refreshing if expired.
|
|
344
236
|
|
|
345
237
|
```tsx
|
|
346
|
-
import { getAccessToken } from '
|
|
238
|
+
import { getAccessToken } from 'tenneo-auth-plugin';
|
|
239
|
+
|
|
347
240
|
const token = await getAccessToken();
|
|
348
241
|
```
|
|
349
242
|
|
|
350
|
-
|
|
243
|
+
### logout()
|
|
351
244
|
|
|
352
|
-
|
|
245
|
+
Signs out the user and clears all authentication data.
|
|
353
246
|
|
|
354
247
|
```tsx
|
|
355
|
-
import { logout } from '
|
|
248
|
+
import { logout } from 'tenneo-auth-plugin';
|
|
249
|
+
|
|
356
250
|
await logout();
|
|
357
251
|
```
|
|
358
252
|
|
|
359
|
-
###
|
|
360
|
-
|
|
361
|
-
#### `Config` Object
|
|
253
|
+
### createAuthEngine()
|
|
362
254
|
|
|
363
|
-
|
|
255
|
+
Creates an authentication engine instance for advanced use cases.
|
|
364
256
|
|
|
365
257
|
```tsx
|
|
366
|
-
import {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
258
|
+
import { createAuthEngine } from 'tenneo-auth-plugin';
|
|
259
|
+
|
|
260
|
+
const engine = createAuthEngine(runtime);
|
|
261
|
+
|
|
262
|
+
// Subscribe to state changes
|
|
263
|
+
const unsubscribe = engine.subscribe((state) => {
|
|
264
|
+
console.log('Status:', state.status);
|
|
265
|
+
console.log('Token:', state.accessToken);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Initialize
|
|
269
|
+
await engine.init();
|
|
270
|
+
|
|
271
|
+
// Operations
|
|
272
|
+
await engine.login();
|
|
273
|
+
await engine.logout();
|
|
274
|
+
const token = await engine.getAccessToken();
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Configuration
|
|
278
|
+
|
|
279
|
+
### Environment Variables
|
|
280
|
+
|
|
281
|
+
Configure the plugin using environment variables. For Vite applications, use the `VITE_` prefix.
|
|
282
|
+
|
|
283
|
+
```env
|
|
284
|
+
# OAuth Server URL
|
|
285
|
+
VITE_AUTH_SERVER_URL=https://auth.example.com
|
|
286
|
+
|
|
287
|
+
# API Base URLs
|
|
288
|
+
VITE_API_TENANT_RESOLUTION_BASE_URL=https://api.example.com/api/v1
|
|
289
|
+
VITE_API_AUTH_BASE_URL=https://auth.example.com
|
|
290
|
+
|
|
291
|
+
# Default Configuration
|
|
292
|
+
VITE_CLIENT_ID=your-client-id
|
|
293
|
+
VITE_TENANT_ID=your-tenant-id
|
|
294
|
+
VITE_CLIENTCODE=your-tenant-code
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Window Runtime Configuration
|
|
298
|
+
|
|
299
|
+
Inject configuration at runtime without rebuilding the application.
|
|
300
|
+
|
|
301
|
+
```html
|
|
302
|
+
<script>
|
|
303
|
+
window.__AUTH_CONFIG__ = {
|
|
304
|
+
clientId: 'runtime-client-id',
|
|
305
|
+
tenantId: 'runtime-tenant-id',
|
|
306
|
+
basePath: '/app',
|
|
307
|
+
};
|
|
308
|
+
</script>
|
|
375
309
|
```
|
|
376
310
|
|
|
377
|
-
|
|
311
|
+
### Configuration Priority
|
|
378
312
|
|
|
379
|
-
|
|
313
|
+
Configuration is resolved in the following order (highest priority first):
|
|
314
|
+
|
|
315
|
+
1. Props passed to AuthProvider
|
|
316
|
+
2. Window configuration (`window.__AUTH_CONFIG__`)
|
|
317
|
+
3. Environment variables
|
|
318
|
+
4. Built-in defaults
|
|
319
|
+
|
|
320
|
+
### Programmatic Configuration
|
|
380
321
|
|
|
381
322
|
```tsx
|
|
382
|
-
import { setConfig } from '
|
|
323
|
+
import { setConfig, Config } from 'tenneo-auth-plugin';
|
|
383
324
|
|
|
325
|
+
// Override configuration
|
|
384
326
|
setConfig({
|
|
385
327
|
clientId: 'custom-client-id',
|
|
386
328
|
tenantId: 'custom-tenant-id',
|
|
387
329
|
basePath: '/my-app',
|
|
388
|
-
redirectUri: 'https://myapp.com/callback',
|
|
389
330
|
});
|
|
331
|
+
|
|
332
|
+
// Access resolved configuration
|
|
333
|
+
const authServerUrl = Config.getAuthServerUrl();
|
|
334
|
+
const clientId = Config.getClientId();
|
|
335
|
+
const allConfig = Config.getAll();
|
|
390
336
|
```
|
|
391
337
|
|
|
392
|
-
### Storage Adapters
|
|
393
338
|
|
|
394
|
-
|
|
339
|
+
## Security
|
|
340
|
+
|
|
341
|
+
### PKCE Protection
|
|
342
|
+
|
|
343
|
+
The plugin implements PKCE (Proof Key for Code Exchange) to prevent authorization code interception attacks. A cryptographically random code verifier is generated for each authentication request and never transmitted to the authorization server.
|
|
344
|
+
|
|
345
|
+
### CSRF Protection
|
|
346
|
+
|
|
347
|
+
OAuth state parameter validation prevents cross-site request forgery attacks. Each authentication request includes a unique state value that is verified during the callback.
|
|
348
|
+
|
|
349
|
+
### Token Isolation
|
|
350
|
+
|
|
351
|
+
Authentication tokens are stored with tenant-specific namespacing, ensuring complete isolation between different tenants in multi-tenant deployments.
|
|
352
|
+
|
|
353
|
+
### HTTPS Enforcement
|
|
354
|
+
|
|
355
|
+
Production environments automatically enforce HTTPS for all authentication-related requests and redirects.
|
|
356
|
+
|
|
357
|
+
### Session Security
|
|
358
|
+
|
|
359
|
+
Tokens are stored in sessionStorage by default, ensuring they are cleared when the browser tab is closed. For enhanced security requirements, custom storage adapters can be configured.
|
|
360
|
+
|
|
361
|
+
## Storage Adapters
|
|
395
362
|
|
|
396
363
|
```tsx
|
|
397
364
|
import {
|
|
398
365
|
createSecureSessionStorageAdapter,
|
|
399
366
|
createCookieStorageAdapter,
|
|
400
367
|
createMemoryStorageAdapter,
|
|
401
|
-
|
|
402
|
-
} from '@tenneo/auth-plugin';
|
|
368
|
+
} from 'tenneo-auth-plugin';
|
|
403
369
|
|
|
404
|
-
// Session storage (default)
|
|
370
|
+
// Session storage (default, cleared on tab close)
|
|
405
371
|
const sessionAdapter = createSecureSessionStorageAdapter({
|
|
406
372
|
tenantId: 'tenant-123',
|
|
407
373
|
appId: 'my-app'
|
|
408
374
|
});
|
|
409
375
|
|
|
410
|
-
// Cookie storage
|
|
376
|
+
// Cookie storage (persistent)
|
|
411
377
|
const cookieAdapter = createCookieStorageAdapter({
|
|
412
378
|
tenantId: 'tenant-123',
|
|
413
379
|
appId: 'my-app'
|
|
414
380
|
});
|
|
415
381
|
|
|
416
|
-
// Memory storage (
|
|
382
|
+
// Memory storage (testing)
|
|
417
383
|
const memoryAdapter = createMemoryStorageAdapter({
|
|
418
384
|
tenantId: 'tenant-123',
|
|
419
385
|
appId: 'my-app'
|
|
420
386
|
});
|
|
421
387
|
|
|
422
388
|
// Use custom adapter
|
|
423
|
-
<AuthProvider tenantCode="abc" storageAdapter={
|
|
389
|
+
<AuthProvider tenantCode="abc" storageAdapter={sessionAdapter}>
|
|
424
390
|
<App />
|
|
425
391
|
</AuthProvider>
|
|
426
392
|
```
|
|
427
393
|
|
|
428
|
-
|
|
394
|
+
## Events
|
|
429
395
|
|
|
430
|
-
|
|
396
|
+
Subscribe to authentication events for logging, analytics, or custom behavior.
|
|
431
397
|
|
|
432
398
|
```tsx
|
|
433
|
-
import {
|
|
434
|
-
|
|
435
|
-
const engine = createAuthEngine(runtime);
|
|
436
|
-
|
|
437
|
-
// Subscribe to state changes
|
|
438
|
-
const unsubscribe = engine.subscribe((state) => {
|
|
439
|
-
console.log('Auth state:', state.status);
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
// Initialize
|
|
443
|
-
await engine.init();
|
|
444
|
-
|
|
445
|
-
// Get current state
|
|
446
|
-
const state = engine.getState();
|
|
447
|
-
|
|
448
|
-
// Manual operations
|
|
449
|
-
await engine.login();
|
|
450
|
-
await engine.logout();
|
|
451
|
-
await engine.refresh();
|
|
452
|
-
const token = await engine.getAccessToken();
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
### Events
|
|
399
|
+
import { subscribeAuthEvent, AuthEventNames } from 'tenneo-auth-plugin';
|
|
456
400
|
|
|
457
|
-
Subscribe to
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
import {
|
|
461
|
-
subscribeAuthEvent,
|
|
462
|
-
emitAuthEvent,
|
|
463
|
-
AuthEventNames
|
|
464
|
-
} from '@tenneo/auth-plugin';
|
|
465
|
-
|
|
466
|
-
// Subscribe to events
|
|
467
|
-
const unsubscribe = subscribeAuthEvent('auth:login', (payload) => {
|
|
468
|
-
console.log('User logged in');
|
|
401
|
+
// Subscribe to login events
|
|
402
|
+
const unsubscribe = subscribeAuthEvent(AuthEventNames.LOGIN, (payload) => {
|
|
403
|
+
console.log('User authenticated');
|
|
469
404
|
});
|
|
470
405
|
|
|
471
406
|
// Available events
|
|
472
|
-
AuthEventNames.LOGIN
|
|
473
|
-
AuthEventNames.LOGOUT
|
|
474
|
-
AuthEventNames.REFRESH
|
|
475
|
-
AuthEventNames.ERROR
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
## Environment Variables
|
|
479
|
-
|
|
480
|
-
Configure the plugin via environment variables (Vite apps use `VITE_` prefix):
|
|
481
|
-
|
|
482
|
-
```env
|
|
483
|
-
# Auth Server URL - Your OAuth authorization server
|
|
484
|
-
VITE_AUTH_SERVER_URL=https://auth.example.com
|
|
485
|
-
|
|
486
|
-
# API base URLs
|
|
487
|
-
VITE_API_TENANT_RESOLUTION_BASE_URL=https://api.example.com/api/v1
|
|
488
|
-
VITE_API_AUTH_BASE_URL=https://auth.example.com
|
|
489
|
-
|
|
490
|
-
# Default values (optional)
|
|
491
|
-
VITE_CLIENT_ID=your-client-id
|
|
492
|
-
VITE_TENANT_ID=your-tenant-id
|
|
493
|
-
VITE_CLIENTCODE=your-tenant-code
|
|
407
|
+
AuthEventNames.LOGIN // User successfully authenticated
|
|
408
|
+
AuthEventNames.LOGOUT // User signed out
|
|
409
|
+
AuthEventNames.REFRESH // Token refreshed
|
|
410
|
+
AuthEventNames.ERROR // Authentication error occurred
|
|
494
411
|
```
|
|
495
412
|
|
|
496
|
-
|
|
413
|
+
## TypeScript Support
|
|
497
414
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
For runtime configuration without rebuilding:
|
|
501
|
-
|
|
502
|
-
```html
|
|
503
|
-
<script>
|
|
504
|
-
window.__AUTH_CONFIG__ = {
|
|
505
|
-
clientId: 'runtime-client-id',
|
|
506
|
-
tenantId: 'runtime-tenant-id',
|
|
507
|
-
basePath: '/my-app',
|
|
508
|
-
};
|
|
509
|
-
</script>
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
## Architecture
|
|
513
|
-
|
|
514
|
-
```
|
|
515
|
-
@tenneo/auth-plugin/
|
|
516
|
-
└── src/
|
|
517
|
-
├── index.ts # Main exports
|
|
518
|
-
├── application/ # Application layer (bootstrap, flows, engine)
|
|
519
|
-
│ ├── bootstrap.ts # Auth initialization
|
|
520
|
-
│ ├── engine/ # Auth state machine
|
|
521
|
-
│ ├── flows/ # OAuth flow implementations
|
|
522
|
-
│ └── events/ # Event system
|
|
523
|
-
├── infrastructure/ # Infrastructure adapters
|
|
524
|
-
│ ├── storage/ # Storage adapters
|
|
525
|
-
│ ├── runtime/ # Runtime context
|
|
526
|
-
│ ├── tenant/ # Tenant resolution
|
|
527
|
-
│ └── watchers/ # Storage/cookie watchers
|
|
528
|
-
├── strategies/ # Auth strategies
|
|
529
|
-
│ └── oauth2-pkce/ # OAuth 2.0 PKCE implementation
|
|
530
|
-
├── context/ # React Context
|
|
531
|
-
├── components/ # React components
|
|
532
|
-
├── hooks/ # React hooks
|
|
533
|
-
├── config/ # Configuration
|
|
534
|
-
├── domain/ # Domain types
|
|
535
|
-
└── utils/ # Utilities
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
## Storage Keys
|
|
539
|
-
|
|
540
|
-
Authentication data is stored with namespaced keys (`auth_{tenantId}_{appId}_*`):
|
|
541
|
-
|
|
542
|
-
- `*_access_token` - Current access token
|
|
543
|
-
- `*_refresh_token` - Refresh token
|
|
544
|
-
- `*_expires_at` - Token expiration timestamp
|
|
545
|
-
- `*_id_token` - ID token (if provided)
|
|
546
|
-
- `*_tenant_id` - Resolved tenant ID
|
|
547
|
-
- `*_tenant_key` - Tenant code/key
|
|
548
|
-
- `*_code_verifier` - PKCE code verifier (temporary)
|
|
549
|
-
- `*_state` - OAuth state parameter (temporary)
|
|
550
|
-
|
|
551
|
-
## TypeScript Types
|
|
552
|
-
|
|
553
|
-
All types are exported for use in your application:
|
|
415
|
+
All types are exported for use in TypeScript applications.
|
|
554
416
|
|
|
555
417
|
```tsx
|
|
556
418
|
import type {
|
|
@@ -565,31 +427,17 @@ import type {
|
|
|
565
427
|
AuthEngineState,
|
|
566
428
|
SDKConfig,
|
|
567
429
|
RuntimeConfigOverrides,
|
|
568
|
-
} from '
|
|
430
|
+
} from 'tenneo-auth-plugin';
|
|
569
431
|
```
|
|
570
432
|
|
|
571
|
-
##
|
|
433
|
+
## Versioning
|
|
434
|
+
|
|
435
|
+
This package follows Semantic Versioning (SemVer):
|
|
572
436
|
|
|
573
|
-
-
|
|
574
|
-
-
|
|
575
|
-
-
|
|
576
|
-
-
|
|
577
|
-
- Secure cookie options for cookie-based storage
|
|
578
|
-
|
|
579
|
-
npm run clean # Remove dist/
|
|
580
|
-
npm run build # Build with tsup
|
|
581
|
-
npm run dev # Watch mode
|
|
582
|
-
npm run type-check # TypeScript check
|
|
583
|
-
npm run release:beta # Publish beta version (restricted)
|
|
584
|
-
npm run release:minor # Publish minor version (restricted)
|
|
585
|
-
npm run release:major # Publish major version (restricted)
|
|
586
|
-
|
|
587
|
-
Publishing
|
|
588
|
-
npm login
|
|
589
|
-
npm run release:beta # First beta release
|
|
590
|
-
|
|
591
|
-
Consumers install via:
|
|
592
|
-
npm install @tenneo/auth-plugin@beta
|
|
437
|
+
- **Major versions** contain breaking changes
|
|
438
|
+
- **Minor versions** add backward-compatible features
|
|
439
|
+
- **Patch versions** include backward-compatible bug fixes
|
|
440
|
+
- **Beta versions** are pre-release versions for testing
|
|
593
441
|
|
|
594
442
|
## License
|
|
595
443
|
|