@owlmeans/oidc 0.1.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/LICENSE +21 -0
- package/README.md +525 -0
- package/build/.gitkeep +0 -0
- package/build/consts.d.ts +17 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +17 -0
- package/build/consts.js.map +1 -0
- package/build/guard.d.ts +6 -0
- package/build/guard.d.ts.map +1 -0
- package/build/guard.js +102 -0
- package/build/guard.js.map +1 -0
- package/build/index.d.ts +6 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/models.d.ts +7 -0
- package/build/models.d.ts.map +1 -0
- package/build/models.js +58 -0
- package/build/models.js.map +1 -0
- package/build/modules.d.ts +2 -0
- package/build/modules.d.ts.map +1 -0
- package/build/modules.js +9 -0
- package/build/modules.js.map +1 -0
- package/build/types.d.ts +88 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +44 -0
- package/src/consts.ts +32 -0
- package/src/guard.ts +130 -0
- package/src/index.ts +5 -0
- package/src/models.ts +63 -0
- package/src/modules.ts +16 -0
- package/src/types.ts +116 -0
- package/tsconfig.json +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 OwlMeans Common — Fullstack typescript framework
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
# @owlmeans/oidc
|
|
2
|
+
|
|
3
|
+
OpenID Connect (OIDC) integration library for OwlMeans Common applications. This package provides shared OIDC functionality, including provider configuration, authentication flows, and standardized modules for implementing OIDC relying party and provider services.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The `@owlmeans/oidc` package serves as the foundation for OIDC authentication in the OwlMeans ecosystem, providing:
|
|
8
|
+
|
|
9
|
+
- **OIDC Provider Configuration**: Standardized configuration for OIDC identity providers
|
|
10
|
+
- **Authentication Modules**: Pre-built modules for OIDC authentication flows
|
|
11
|
+
- **Guard Services**: OIDC-based authentication guards for API protection
|
|
12
|
+
- **Client Integration**: Support for OIDC relying party implementations
|
|
13
|
+
- **Provider Support**: Foundation for OIDC identity provider services
|
|
14
|
+
- **Flow Management**: Integration with OwlMeans flow system for authentication workflows
|
|
15
|
+
- **Multi-Provider Support**: Configuration and management of multiple OIDC providers
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @owlmeans/oidc
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Core Concepts
|
|
24
|
+
|
|
25
|
+
### OIDC Provider Configuration
|
|
26
|
+
|
|
27
|
+
The package defines standardized configuration structures for OIDC identity providers, supporting both public and private providers with flexible client configurations.
|
|
28
|
+
|
|
29
|
+
### Authentication Modules
|
|
30
|
+
|
|
31
|
+
Pre-built modules handle OIDC authentication flows, including initialization, callback processing, and token management.
|
|
32
|
+
|
|
33
|
+
### Guard Services
|
|
34
|
+
|
|
35
|
+
OIDC guards provide authentication and authorization for API endpoints using OIDC tokens.
|
|
36
|
+
|
|
37
|
+
### Multi-Tenant Support
|
|
38
|
+
|
|
39
|
+
Support for multiple OIDC providers with entity-specific bindings and restriction capabilities.
|
|
40
|
+
|
|
41
|
+
## API Reference
|
|
42
|
+
|
|
43
|
+
### Types
|
|
44
|
+
|
|
45
|
+
#### `OidcSharedConfig`
|
|
46
|
+
Main configuration interface for OIDC functionality.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
interface OidcSharedConfig {
|
|
50
|
+
clientCookie?: {
|
|
51
|
+
interaction?: {
|
|
52
|
+
name?: string // Cookie name for interactions
|
|
53
|
+
ttl?: number // Time-to-live for interaction cookies
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
providers?: OidcProviderConfig[] // OIDC provider configurations
|
|
57
|
+
restrictedProviders?: boolean | string[] // Provider access restrictions
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### `OidcProviderConfig`
|
|
62
|
+
Configuration for individual OIDC providers.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
interface OidcProviderConfig extends OidcProviderDescriptor {
|
|
66
|
+
internal?: boolean // Internal use only flag
|
|
67
|
+
apiClientId?: string // Administrative client ID
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### `OidcProviderDescriptor`
|
|
72
|
+
Core provider configuration.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
interface OidcProviderDescriptor {
|
|
76
|
+
entityId?: string // Entity binding
|
|
77
|
+
service?: string // Service identifier
|
|
78
|
+
discoveryUrl?: string // OIDC discovery endpoint
|
|
79
|
+
basePath?: string // Base path for OIDC endpoints
|
|
80
|
+
clientId: string // OAuth2 client ID
|
|
81
|
+
secret?: string // Client secret
|
|
82
|
+
extraScopes?: string // Additional OAuth2 scopes
|
|
83
|
+
idOverride?: string // Provider ID override
|
|
84
|
+
def?: boolean // Default provider flag (client-side)
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### `WithSharedConfig`
|
|
89
|
+
Interface for configurations that include OIDC settings.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
interface WithSharedConfig {
|
|
93
|
+
oidc: OidcSharedConfig
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Constants
|
|
98
|
+
|
|
99
|
+
#### Module Identifiers
|
|
100
|
+
```typescript
|
|
101
|
+
const OIDC_AUTHEN_MODULE = 'iam-oidc-authen' // OIDC authentication module
|
|
102
|
+
const PROVIDER_INTERACTION = 'oidc-server:interaction' // Provider interaction module
|
|
103
|
+
const OIDC_CLIENT_AUTH = 'oidc-client' // Client authentication module
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Flow and Guard Constants
|
|
107
|
+
```typescript
|
|
108
|
+
const OIDC_FLOW = 'oidc' // OIDC authentication flow
|
|
109
|
+
const OIDC_GUARD = 'guard:oidc' // OIDC guard service
|
|
110
|
+
const OIDC_GUARD_CACHE = 'resource:oidc-guard:cache' // Guard cache resource
|
|
111
|
+
const OIDC_GATE = 'oidc-gate' // OIDC gate service
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### Dispatcher Constants
|
|
115
|
+
```typescript
|
|
116
|
+
const DISPATCHER_OIDC_INIT = 'dispatcher:oidc:init' // OIDC initialization
|
|
117
|
+
const DISPATCHER_OIDC = 'dispatcher:oidc:authenticate' // OIDC authentication
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### Path and Parameter Constants
|
|
121
|
+
```typescript
|
|
122
|
+
const DEFAULT_PATH = 'oidc' // Default OIDC base path
|
|
123
|
+
const DEFAULT_FRONT = 'oidc-client' // Default frontend identifier
|
|
124
|
+
const INTERACTION_PATH = '/interaction/:uid' // Interaction endpoint path
|
|
125
|
+
const OIDC_CODE_QUERY = 'code' // Authorization code query parameter
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Pre-built Modules
|
|
129
|
+
|
|
130
|
+
The package exports pre-configured modules for OIDC authentication:
|
|
131
|
+
|
|
132
|
+
#### OIDC Initialization Module
|
|
133
|
+
Handles OIDC authentication initialization requests.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// Route: POST /authenticate/oidc/init
|
|
137
|
+
// Validates: OIDCAuthInitParamsSchema
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### OIDC Processing Module
|
|
141
|
+
Handles OIDC authentication callback processing.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// Route: POST /authenticate/oidc/process
|
|
145
|
+
// Validates: OIDCClientAuthPayloadSchema
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Usage Examples
|
|
149
|
+
|
|
150
|
+
### Basic OIDC Configuration
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { OidcSharedConfig } from '@owlmeans/oidc'
|
|
154
|
+
|
|
155
|
+
const oidcConfig: OidcSharedConfig = {
|
|
156
|
+
clientCookie: {
|
|
157
|
+
interaction: {
|
|
158
|
+
name: 'oidc_interaction',
|
|
159
|
+
ttl: 3600 // 1 hour
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
providers: [
|
|
163
|
+
{
|
|
164
|
+
clientId: 'my-app-client',
|
|
165
|
+
secret: 'client-secret',
|
|
166
|
+
discoveryUrl: 'https://auth.example.com/.well-known/openid_configuration',
|
|
167
|
+
extraScopes: 'profile email',
|
|
168
|
+
def: true // Default provider
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Multi-Provider Configuration
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const multiProviderConfig: OidcSharedConfig = {
|
|
178
|
+
providers: [
|
|
179
|
+
{
|
|
180
|
+
clientId: 'google-client-id',
|
|
181
|
+
discoveryUrl: 'https://accounts.google.com/.well-known/openid_configuration',
|
|
182
|
+
service: 'google',
|
|
183
|
+
extraScopes: 'profile email'
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
clientId: 'microsoft-client-id',
|
|
187
|
+
discoveryUrl: 'https://login.microsoftonline.com/common/v2.0/.well-known/openid_configuration',
|
|
188
|
+
service: 'microsoft',
|
|
189
|
+
extraScopes: 'profile email'
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
clientId: 'internal-client-id',
|
|
193
|
+
secret: 'internal-secret',
|
|
194
|
+
discoveryUrl: 'https://internal-auth.company.com/.well-known/openid_configuration',
|
|
195
|
+
service: 'internal',
|
|
196
|
+
internal: true, // Internal use only
|
|
197
|
+
entityId: 'company-employees'
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
restrictedProviders: ['internal'] // Restrict access to internal provider
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Entity-Specific Provider Configuration
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const entitySpecificConfig: OidcSharedConfig = {
|
|
208
|
+
providers: [
|
|
209
|
+
{
|
|
210
|
+
clientId: 'org-a-client',
|
|
211
|
+
secret: 'org-a-secret',
|
|
212
|
+
discoveryUrl: 'https://auth-org-a.example.com/.well-known/openid_configuration',
|
|
213
|
+
entityId: 'organization-a',
|
|
214
|
+
service: 'org-a'
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
clientId: 'org-b-client',
|
|
218
|
+
secret: 'org-b-secret',
|
|
219
|
+
discoveryUrl: 'https://auth-org-b.example.com/.well-known/openid_configuration',
|
|
220
|
+
entityId: 'organization-b',
|
|
221
|
+
service: 'org-b'
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### OIDC Module Integration
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { modules } from '@owlmeans/oidc'
|
|
231
|
+
import { createBasicContext } from '@owlmeans/context'
|
|
232
|
+
|
|
233
|
+
// Create context with OIDC modules
|
|
234
|
+
const context = createBasicContext({
|
|
235
|
+
oidc: oidcConfig
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
// Register OIDC modules
|
|
239
|
+
modules.forEach(module => {
|
|
240
|
+
context.registerModule(module)
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
// Initialize context
|
|
244
|
+
await context.init()
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Custom OIDC Module
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
import { module, body, filter } from '@owlmeans/module'
|
|
251
|
+
import { route, RouteMethod, backend } from '@owlmeans/route'
|
|
252
|
+
|
|
253
|
+
const customOidcModule = module(
|
|
254
|
+
route('custom-oidc-login', '/auth/custom/login', backend(null, RouteMethod.POST)),
|
|
255
|
+
filter(body(CustomOIDCSchema)),
|
|
256
|
+
// Custom handler implementation
|
|
257
|
+
async (request, reply) => {
|
|
258
|
+
const { provider, redirectUri } = request.body
|
|
259
|
+
|
|
260
|
+
// Custom OIDC initialization logic
|
|
261
|
+
const authUrl = await generateOIDCAuthUrl(provider, redirectUri)
|
|
262
|
+
|
|
263
|
+
reply.resolve({ authUrl }, ModuleOutcome.Ok)
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### OIDC Guard Usage
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { OIDC_GUARD } from '@owlmeans/oidc'
|
|
272
|
+
|
|
273
|
+
// Protect API endpoint with OIDC guard
|
|
274
|
+
const protectedModule = module(
|
|
275
|
+
route('protected-api', '/api/protected', backend()),
|
|
276
|
+
// Guard will validate OIDC tokens
|
|
277
|
+
{ guards: [OIDC_GUARD] },
|
|
278
|
+
async (request, reply) => {
|
|
279
|
+
// Access authenticated user from OIDC token
|
|
280
|
+
const user = request.auth?.user
|
|
281
|
+
|
|
282
|
+
const data = await getProtectedData(user.id)
|
|
283
|
+
reply.resolve(data)
|
|
284
|
+
}
|
|
285
|
+
)
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Provider Restriction Implementation
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
// Configuration with provider restrictions
|
|
292
|
+
const restrictedConfig: OidcSharedConfig = {
|
|
293
|
+
providers: [
|
|
294
|
+
{ clientId: 'public-provider', service: 'public' },
|
|
295
|
+
{ clientId: 'internal-provider', service: 'internal', internal: true },
|
|
296
|
+
{ clientId: 'partner-provider', service: 'partner' }
|
|
297
|
+
],
|
|
298
|
+
// Only allow internal and partner providers
|
|
299
|
+
restrictedProviders: ['internal', 'partner']
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Check if provider is allowed
|
|
303
|
+
const isProviderAllowed = (providerId: string, config: OidcSharedConfig) => {
|
|
304
|
+
const { restrictedProviders } = config
|
|
305
|
+
|
|
306
|
+
if (restrictedProviders === false) {
|
|
307
|
+
return false // No providers allowed
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (restrictedProviders === true) {
|
|
311
|
+
// Only default provider allowed
|
|
312
|
+
const defaultProvider = config.providers?.find(p => p.def)
|
|
313
|
+
return defaultProvider?.service === providerId
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (Array.isArray(restrictedProviders)) {
|
|
317
|
+
return restrictedProviders.includes(providerId)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return true // All providers allowed
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### OIDC Flow Integration
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
import { OIDC_FLOW } from '@owlmeans/oidc'
|
|
328
|
+
import { makeFlowModel } from '@owlmeans/flow'
|
|
329
|
+
|
|
330
|
+
// Create OIDC authentication flow
|
|
331
|
+
const oidcFlow = await makeFlowModel(OIDC_FLOW, flowProvider)
|
|
332
|
+
|
|
333
|
+
// Start authentication flow
|
|
334
|
+
oidcFlow.target('auth-service')
|
|
335
|
+
oidcFlow.entity('user-123')
|
|
336
|
+
|
|
337
|
+
// Navigate through flow steps
|
|
338
|
+
const initState = oidcFlow.transit('init', true, 'Starting OIDC auth')
|
|
339
|
+
const authState = oidcFlow.transit('authenticate', true, 'Provider selected')
|
|
340
|
+
const completeState = oidcFlow.transit('complete', true, 'Authentication successful')
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Token Validation
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { OIDC_WRAPPED_TOKEN, WRAPPED_OIDC } from '@owlmeans/oidc'
|
|
347
|
+
|
|
348
|
+
// Validate OIDC token
|
|
349
|
+
const validateOIDCToken = async (token: string, providerId: string) => {
|
|
350
|
+
// Extract provider configuration
|
|
351
|
+
const provider = oidcConfig.providers?.find(p => p.service === providerId)
|
|
352
|
+
if (!provider) {
|
|
353
|
+
throw new Error('Provider not found')
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Validate token with provider
|
|
357
|
+
const tokenInfo = await validateWithProvider(token, provider)
|
|
358
|
+
|
|
359
|
+
// Wrap token for internal use
|
|
360
|
+
return {
|
|
361
|
+
type: OIDC_WRAPPED_TOKEN,
|
|
362
|
+
token: tokenInfo.access_token,
|
|
363
|
+
user: tokenInfo.userInfo,
|
|
364
|
+
provider: providerId
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Custom Provider Discovery
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
// Dynamic provider discovery
|
|
373
|
+
const discoverOIDCProvider = async (discoveryUrl: string) => {
|
|
374
|
+
const response = await fetch(discoveryUrl)
|
|
375
|
+
const discovery = await response.json()
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
authorizationEndpoint: discovery.authorization_endpoint,
|
|
379
|
+
tokenEndpoint: discovery.token_endpoint,
|
|
380
|
+
userinfoEndpoint: discovery.userinfo_endpoint,
|
|
381
|
+
jwksUri: discovery.jwks_uri,
|
|
382
|
+
issuer: discovery.issuer
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Use discovered endpoints
|
|
387
|
+
const provider: OidcProviderConfig = {
|
|
388
|
+
clientId: 'dynamic-client',
|
|
389
|
+
discoveryUrl: 'https://example.com/.well-known/openid_configuration',
|
|
390
|
+
service: 'dynamic-provider'
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const endpoints = await discoverOIDCProvider(provider.discoveryUrl!)
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Advanced Features
|
|
397
|
+
|
|
398
|
+
### Administrative API Integration
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
// Provider with administrative capabilities
|
|
402
|
+
const adminProviderConfig: OidcProviderConfig = {
|
|
403
|
+
clientId: 'public-client-id',
|
|
404
|
+
secret: 'public-client-secret',
|
|
405
|
+
discoveryUrl: 'https://auth.example.com/.well-known/openid_configuration',
|
|
406
|
+
apiClientId: 'admin-client-id', // For administrative operations
|
|
407
|
+
service: 'managed-provider'
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Use administrative client for user management
|
|
411
|
+
const manageUsers = async (provider: OidcProviderConfig) => {
|
|
412
|
+
const adminToken = await getAdminToken(provider.apiClientId!)
|
|
413
|
+
|
|
414
|
+
// Perform administrative operations
|
|
415
|
+
const users = await listUsers(adminToken)
|
|
416
|
+
return users
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Cookie Configuration
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// Custom cookie configuration for interactions
|
|
424
|
+
const cookieConfig: OidcSharedConfig = {
|
|
425
|
+
clientCookie: {
|
|
426
|
+
interaction: {
|
|
427
|
+
name: 'app_oidc_session',
|
|
428
|
+
ttl: 7200 // 2 hours
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Use in OIDC interaction handling
|
|
434
|
+
const handleInteraction = (req: Request, res: Response) => {
|
|
435
|
+
const cookieName = cookieConfig.clientCookie?.interaction?.name || 'oidc_interaction'
|
|
436
|
+
const ttl = cookieConfig.clientCookie?.interaction?.ttl || 3600
|
|
437
|
+
|
|
438
|
+
res.cookie(cookieName, interactionData, {
|
|
439
|
+
maxAge: ttl * 1000,
|
|
440
|
+
httpOnly: true,
|
|
441
|
+
secure: true
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Error Handling
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
import { OIDCError } from '@owlmeans/oidc'
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
const result = await authenticateWithOIDC(provider, token)
|
|
453
|
+
return result
|
|
454
|
+
} catch (error) {
|
|
455
|
+
if (error instanceof OIDCError) {
|
|
456
|
+
console.error('OIDC authentication failed:', error.message)
|
|
457
|
+
|
|
458
|
+
// Handle specific OIDC errors
|
|
459
|
+
switch (error.code) {
|
|
460
|
+
case 'invalid_token':
|
|
461
|
+
// Handle invalid token
|
|
462
|
+
break
|
|
463
|
+
case 'provider_unavailable':
|
|
464
|
+
// Handle provider unavailability
|
|
465
|
+
break
|
|
466
|
+
default:
|
|
467
|
+
// Handle generic OIDC error
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
throw error
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
## Integration with OwlMeans Ecosystem
|
|
476
|
+
|
|
477
|
+
The `@owlmeans/oidc` package integrates with:
|
|
478
|
+
|
|
479
|
+
- **@owlmeans/auth**: Core authentication types and interfaces
|
|
480
|
+
- **@owlmeans/auth-common**: Common authentication utilities and guards
|
|
481
|
+
- **@owlmeans/module**: Module system for OIDC endpoints
|
|
482
|
+
- **@owlmeans/route**: Routing system for OIDC flows
|
|
483
|
+
- **@owlmeans/flow**: Flow management for authentication workflows
|
|
484
|
+
- **@owlmeans/context**: Configuration and service management
|
|
485
|
+
- **@owlmeans/server-oidc-provider**: Server-side OIDC provider implementation
|
|
486
|
+
- **@owlmeans/server-oidc-rp**: Server-side relying party implementation
|
|
487
|
+
- **@owlmeans/web-oidc-rp**: Web-based relying party implementation
|
|
488
|
+
|
|
489
|
+
## Security Considerations
|
|
490
|
+
|
|
491
|
+
- Always use HTTPS for OIDC endpoints and redirects
|
|
492
|
+
- Validate all tokens received from OIDC providers
|
|
493
|
+
- Implement proper CSRF protection for authentication flows
|
|
494
|
+
- Use secure cookies for session management
|
|
495
|
+
- Validate provider discovery documents
|
|
496
|
+
- Implement proper token storage and cleanup
|
|
497
|
+
- Use appropriate scopes and minimize requested permissions
|
|
498
|
+
|
|
499
|
+
## Best Practices
|
|
500
|
+
|
|
501
|
+
### Configuration Management
|
|
502
|
+
- Store client secrets securely using environment variables
|
|
503
|
+
- Use discovery URLs when possible for dynamic configuration
|
|
504
|
+
- Implement proper provider validation and filtering
|
|
505
|
+
- Regular review and rotation of client credentials
|
|
506
|
+
|
|
507
|
+
### Multi-Provider Setup
|
|
508
|
+
- Use meaningful service identifiers for providers
|
|
509
|
+
- Implement proper provider selection UI/UX
|
|
510
|
+
- Handle provider-specific error scenarios
|
|
511
|
+
- Implement fallback authentication methods
|
|
512
|
+
|
|
513
|
+
### Security
|
|
514
|
+
- Validate all OIDC tokens before trusting claims
|
|
515
|
+
- Implement proper session timeout and cleanup
|
|
516
|
+
- Use appropriate redirect URI validation
|
|
517
|
+
- Monitor for suspicious authentication patterns
|
|
518
|
+
|
|
519
|
+
### Performance
|
|
520
|
+
- Cache provider discovery documents appropriately
|
|
521
|
+
- Implement efficient token validation
|
|
522
|
+
- Use connection pooling for provider communication
|
|
523
|
+
- Monitor and optimize authentication flow performance
|
|
524
|
+
|
|
525
|
+
Fixes #32.
|
package/build/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const DEFAULT_PATH = "oidc";
|
|
2
|
+
export declare const DEFAULT_FRONT = "oidc-client";
|
|
3
|
+
export declare const INTERACTION_PATH = "/interaction/:uid";
|
|
4
|
+
export declare const INTERACTION = "oidc:interaction";
|
|
5
|
+
export declare const OIDC_FLOW = "oidc";
|
|
6
|
+
export declare const OIDC_AUTHEN_MODULE = "iam-oidc-authen";
|
|
7
|
+
export declare const PROVIDER_INTERACTION = "oidc-server:interaction";
|
|
8
|
+
export declare const OIDC_CLIENT_AUTH = "oidc-client";
|
|
9
|
+
export declare const OIDC_GUARD = "guard:oidc";
|
|
10
|
+
export declare const OIDC_GUARD_CACHE = "resource:oidc-guard:cache";
|
|
11
|
+
export declare const DISPATCHER_OIDC_INIT = "dispatcher:oidc:init";
|
|
12
|
+
export declare const DISPATCHER_OIDC = "dispatcher:oidc:authenticate";
|
|
13
|
+
export declare const OIDC_CODE_QUERY = "code";
|
|
14
|
+
export declare const OIDC_WRAPPED_TOKEN = "oidc-wrapped-token";
|
|
15
|
+
export declare const WRAPPED_OIDC = "wrapped-oidc-authz";
|
|
16
|
+
export declare const OIDC_GATE = "oidc-gate";
|
|
17
|
+
//# sourceMappingURL=consts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,YAAY,SAAS,CAAA;AAElC,eAAO,MAAM,aAAa,gBAAgB,CAAA;AAE1C,eAAO,MAAM,gBAAgB,sBAAsB,CAAA;AAEnD,eAAO,MAAM,WAAW,qBAAqB,CAAA;AAE7C,eAAO,MAAM,SAAS,SAAS,CAAA;AAE/B,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,eAAO,MAAM,oBAAoB,4BAA4B,CAAA;AAE7D,eAAO,MAAM,gBAAgB,gBAAgB,CAAA;AAE7C,eAAO,MAAM,UAAU,eAAe,CAAA;AAEtC,eAAO,MAAM,gBAAgB,8BAA8B,CAAA;AAE3D,eAAO,MAAM,oBAAoB,yBAAyB,CAAA;AAE1D,eAAO,MAAM,eAAe,iCAAiC,CAAA;AAE7D,eAAO,MAAM,eAAe,SAAS,CAAA;AAErC,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AAEtD,eAAO,MAAM,YAAY,uBAAuB,CAAA;AAEhD,eAAO,MAAM,SAAS,cAAc,CAAA"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const DEFAULT_PATH = 'oidc';
|
|
2
|
+
export const DEFAULT_FRONT = 'oidc-client';
|
|
3
|
+
export const INTERACTION_PATH = '/interaction/:uid';
|
|
4
|
+
export const INTERACTION = 'oidc:interaction';
|
|
5
|
+
export const OIDC_FLOW = 'oidc';
|
|
6
|
+
export const OIDC_AUTHEN_MODULE = 'iam-oidc-authen';
|
|
7
|
+
export const PROVIDER_INTERACTION = 'oidc-server:interaction';
|
|
8
|
+
export const OIDC_CLIENT_AUTH = 'oidc-client';
|
|
9
|
+
export const OIDC_GUARD = 'guard:oidc';
|
|
10
|
+
export const OIDC_GUARD_CACHE = 'resource:oidc-guard:cache';
|
|
11
|
+
export const DISPATCHER_OIDC_INIT = 'dispatcher:oidc:init';
|
|
12
|
+
export const DISPATCHER_OIDC = 'dispatcher:oidc:authenticate';
|
|
13
|
+
export const OIDC_CODE_QUERY = 'code';
|
|
14
|
+
export const OIDC_WRAPPED_TOKEN = 'oidc-wrapped-token';
|
|
15
|
+
export const WRAPPED_OIDC = 'wrapped-oidc-authz';
|
|
16
|
+
export const OIDC_GATE = 'oidc-gate';
|
|
17
|
+
//# sourceMappingURL=consts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAA;AAElC,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAA;AAE1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAA;AAEnD,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAA;AAE7C,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAA;AAE/B,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAA;AAEnD,MAAM,CAAC,MAAM,oBAAoB,GAAG,yBAAyB,CAAA;AAE7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAA;AAE7C,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAA;AAEtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAA;AAE3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAA;AAE1D,MAAM,CAAC,MAAM,eAAe,GAAG,8BAA8B,CAAA;AAE7D,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAA;AAErC,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAA;AAEtD,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAA;AAEhD,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAA"}
|
package/build/guard.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Config, Context, OidcGuard, OidcGuardOptions } from './types.js';
|
|
2
|
+
import type { CommonModule } from '@owlmeans/module';
|
|
3
|
+
export declare const makeOidcGuard: (opts?: OidcGuardOptions) => OidcGuard;
|
|
4
|
+
export declare const appendOidcGuard: <C extends Config, T extends Context<C>>(context: T, opts?: OidcGuardOptions) => T;
|
|
5
|
+
export declare const setupOidcGuard: (modules: CommonModule[], coguards?: string | string[]) => void;
|
|
6
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAsB,MAAM,YAAY,CAAA;AAElG,OAAO,KAAK,EAAqC,YAAY,EAAgB,MAAM,kBAAkB,CAAA;AASrG,eAAO,MAAM,aAAa,UAAW,gBAAgB,KAAG,SA4FvD,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,WAC3D,CAAC,SAAS,gBAAgB,MAKpC,CAAA;AAED,eAAO,MAAM,cAAc,YAAa,YAAY,EAAE,aAAa,MAAM,GAAG,MAAM,EAAE,SAUnF,CAAA"}
|