@bigso/auth-sdk 0.4.7 → 0.5.1

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 CHANGED
@@ -1,188 +1,233 @@
1
1
  # @bigso/auth-sdk
2
2
 
3
- SDK oficial de autenticación para Bigso SSO, compatible con el estándar SSO v2.3. Este paquete permite integrar aplicaciones web con el flujo de autenticación basado en iframe seguro, utilizando PKCE, JWS firmados y comunicación mediante postMessage.
3
+ SDK oficial de autenticación para Bigso SSO v2. Flujo basado en JWT Bearer tokens con PKCE, comunicación por iframe seguro, y validación JWKS.
4
4
 
5
- ## 🚀 Características
5
+ ## Características
6
6
 
7
- **Flujo seguro** con PKCE obligatorio y JWS firmado.
7
+ - **Flujo PKCE completo** codeVerifier se expone al consuming app para enviar al backend
8
+ - **JWT Bearer tokens** — accessToken + refreshToken con revoke y rotación automática
9
+ - **Comunicación por iframe** con postMessage v2.3 y validación de origen
10
+ - **JWS verification** en frontend con JWKS remoto
11
+ - **3 entry points**: Browser, Node.js, Express middleware
12
+ - **Server-to-server** login, exchange, refresh, logout via API v2
8
13
 
9
- **Compatible con SSO v2.3** (whitelist de origins, kid en JWS, validación de nonce, timeout reactivo).
14
+ ## Instalación
10
15
 
11
- ✅ **Manejo automático de estados** (state, nonce, verifier, requestId).
12
-
13
- ✅ **Verificación de firma JWS** en el frontend usando `jose` y JWKS remoto.
16
+ ```bash
17
+ npm install @bigso/auth-sdk
18
+ ```
14
19
 
15
- **Timeout reactivo configurable**, activado tras `sso-ready`.
20
+ ## Arquitectura v2
16
21
 
17
- ✅ **Soporte para redirect_uri y tenant_hint**.
22
+ ```
23
+ ┌──────────────┐ postMessage (v2.3) ┌──────────────┐
24
+ │ App Web │◄──────────────────────────►│ SSO Portal │
25
+ │ (consuming) │ sso-init / sso-success │ (iframe) │
26
+ └──────┬───────┘ └──────┬───────┘
27
+ │ │
28
+ │ 1. auth.login() → codeVerifier │
29
+ │ 2. POST /exchange-v2-pkce │
30
+ │ { code, codeVerifier } │
31
+ ▼ ▼
32
+ ┌──────────────┐ POST /api/v2/auth/exchange ┌──────────────┐
33
+ │ App Backend │──────────────────────────────────►│ SSO Core │
34
+ │ (Express) │◄─────────────────────────────────│ (API v2) │
35
+ │ │ { accessToken, refreshToken } │ │
36
+ └──────────────┘ └──────────────┘
37
+ ```
18
38
 
19
- **Manejo de errores** incluyendo `version_mismatch` con fallback automático.
39
+ ## Uso
20
40
 
21
- **API asíncrona** basada en promesas.
41
+ ### Browser (iframe login)
22
42
 
23
- ✅ **Sistema de eventos** (ready, success, error, fallback, debug).
43
+ ```typescript
44
+ import { BigsoAuth } from '@bigso/auth-sdk';
24
45
 
25
- **Ligero** (~6 kB) y con tipos TypeScript.
46
+ const auth = new BigsoAuth({
47
+ clientId: 'crm',
48
+ ssoOrigin: 'https://sso.bigso.co',
49
+ jwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
50
+ });
26
51
 
27
- ## 📦 Instalación
52
+ auth.on('success', async (result) => {
53
+ // result.code → authorization code
54
+ // result.codeVerifier → PKCE verifier (send to your backend!)
55
+ // result.signed_payload → JWS signed payload
56
+ // result.state → matches your original state
57
+ // result.nonce → matches your original nonce
58
+
59
+ // Send to your backend:
60
+ const response = await fetch('/api/auth/exchange-v2-pkce', {
61
+ method: 'POST',
62
+ headers: { 'Content-Type': 'application/json' },
63
+ body: JSON.stringify({
64
+ payload: result.signed_payload,
65
+ }),
66
+ });
67
+ });
28
68
 
29
- ```bash
30
- npm install @bigso/auth-sdk
31
- # o
32
- yarn add @bigso/auth-sdk
33
- # o
34
- pnpm add @bigso/auth-sdk
69
+ auth.login();
35
70
  ```
36
71
 
37
- ## 🧪 Uso básico
72
+ ### Express backend
38
73
 
39
74
  ```typescript
40
- import { BigsoAuth } from '@bigso/auth-sdk';
75
+ import { BigsoSsoClient } from '@bigso/auth-sdk/node';
76
+ import { createSsoAuthRouter, ssoAuthMiddleware } from '@bigso/auth-sdk/express';
41
77
 
42
- const auth = new BigsoAuth({
43
- clientId: 'tu-client-id',
44
- ssoOrigin: 'https://sso.tudominio.com',
45
- jwksUrl: 'https://sso.tudominio.com/.well-known/jwks.json',
46
- timeout: 5000, // opcional, por defecto 5000ms
47
- debug: true, // opcional, logs de depuración
48
- redirectUri: 'https://miapp.com/callback', // opcional
49
- tenantHint: 'mi-tenant' // opcional
78
+ const ssoClient = new BigsoSsoClient({
79
+ ssoBackendUrl: 'https://sso.bigso.co',
80
+ ssoJwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
81
+ appId: 'crm',
50
82
  });
51
83
 
52
- auth.on('ready', () => console.log('✅ Iframe listo'));
53
- auth.on('success', (payload) => {
54
- console.log('✅ Autenticación exitosa', payload);
55
- // Envía el signed_payload al backend para canjear el código
56
- enviarAlBackend(payload.signed_payload);
57
- });
58
- auth.on('error', (error) => console.error('❌ Error:', error));
59
- auth.on('fallback', () => console.log('⚠️ Fallback por redirección activado'));
84
+ // Auth routes: /exchange, /exchange-v2, /session, /refresh, /logout
85
+ app.use('/api/auth', createSsoAuthRouter({
86
+ ssoClient,
87
+ frontendUrl: 'https://myapp.com',
88
+ }));
60
89
 
61
- auth.login().catch(err => console.error('Login falló', err));
90
+ // Protected routes: validates Bearer JWT token
91
+ app.get('/api/protected', ssoAuthMiddleware({ ssoClient }), (req, res) => {
92
+ res.json({ user: req.user, tenant: req.tenant });
93
+ });
62
94
  ```
63
95
 
64
- ## 📚 API Reference
96
+ ### Node.js (server-to-server)
65
97
 
66
- ### `new BigsoAuth(options)`
67
- Crea una nueva instancia del cliente de autenticación.
98
+ ```typescript
99
+ import { BigsoSsoClient } from '@bigso/auth-sdk/node';
68
100
 
69
- #### Opciones de configuración
70
- | Parámetro | Tipo | Obligatorio | Por defecto | Descripción |
71
- | :--- | :--- | :---: | :---: | :--- |
72
- | `clientId` | `string` | ✅ | — | Client ID registrado en el SSO. |
73
- | `ssoOrigin` | `string` | ✅ | — | Origen del SSO (ej. `https://sso.bigso.co`). |
74
- | `jwksUrl` | `string` | ✅ | — | URL del JWKS para verificar firmas (ej. `/.well-known/jwks.json`). |
75
- | `timeout` | `number` | ❌ | `5000` | Tiempo máximo de espera tras `sso-ready` (milisegundos). |
76
- | `debug` | `boolean` | ❌ | `false` | Activa logs de depuración en consola. |
77
- | `redirectUri` | `string` | ❌ | `''` | URI de redirección registrada (se valida exactamente en el SSO). |
78
- | `tenantHint` | `string` | ❌ | `''` | Sugerencia de tenant para flujos multi-tenant. |
101
+ const client = new BigsoSsoClient({
102
+ ssoBackendUrl: 'https://sso.bigso.co',
103
+ ssoJwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
104
+ appId: 'crm',
105
+ });
79
106
 
80
- ### `auth.login()`
81
- Inicia el flujo de autenticación. Devuelve una promesa que se resuelve con el payload decodificado del JWS (solo para información; la validación final debe realizarse en el backend).
107
+ // Exchange authorization code with PKCE
108
+ const session = await client.exchangeCode('ac_abc123...', 'dBjftJeZ4CVP...');
82
109
 
83
- **Retorna**: `Promise<any>` Payload del JWS (contiene `code`, `state`, `nonce`, `iss`, etc.).
110
+ // Validate an access token locally (no network call)
111
+ const payload = await client.validateAccessToken('eyJhbG...');
84
112
 
85
- **Rechaza**: `Error` o payload de error del iframe.
113
+ // Refresh tokens (uses httpOnly cookie)
114
+ const refreshed = await client.refreshTokens();
86
115
 
87
- ### `auth.abort()`
88
- Cancela el flujo de autenticación en curso, eliminando el iframe y rechazando la promesa.
116
+ // Logout
117
+ await client.logout('eyJhbG...', true); // revokeAll = true
118
+ ```
89
119
 
90
- ### `auth.on(event, handler)`
91
- Registra un manejador para los eventos del SDK.
120
+ ## API Reference
92
121
 
93
- #### Eventos disponibles:
94
- | Evento | Descripción | Parámetros |
95
- | :--- | :--- | :--- |
96
- | `ready` | Se emite cuando el iframe está listo y se ha enviado `sso-init`. | — |
97
- | `success` | Se emite tras verificar exitosamente la firma JWS y validar `state`/`nonce` en el frontend. | `payload: any` (payload del JWS) |
98
- | `error` | Se emite cuando ocurre un error (incluyendo `version_mismatch` antes del fallback automático). | `error: Error | SsoErrorPayload` |
99
- | `fallback` | Se emite justo antes de redirigir a la URL de fallback (por timeout o `version_mismatch`). | — |
100
- | `debug` | Se emite cuando `debug: true` para logs internos. | `args: any[]` |
122
+ ### Browser: `BigsoAuth`
101
123
 
102
- ## ⚙️ Ejemplos avanzados
124
+ #### Constructor
103
125
 
104
- ### Personalizar el timeout
105
- ```typescript
106
- const auth = new BigsoAuth({
107
- clientId: 'abc123',
108
- ssoOrigin: 'https://sso.bigso.co',
109
- jwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
110
- timeout: 10000 // 10 segundos
111
- });
112
- ```
126
+ | Param | Type | Required | Default | Description |
127
+ |---|---|---|---|---|
128
+ | `clientId` | `string` | Yes | — | App ID registered in SSO |
129
+ | `ssoOrigin` | `string` | Yes | — | SSO origin (e.g. `https://sso.bigso.co`) |
130
+ | `jwksUrl` | `string` | Yes | — | JWKS URL for JWS verification |
131
+ | `timeout` | `number` | No | `5000` | Timeout after `sso-ready` (ms) |
132
+ | `debug` | `boolean` | No | `false` | Debug logging |
133
+ | `redirectUri` | `string` | No | `''` | Redirect URI |
134
+ | `tenantHint` | `string` | No | `''` | Tenant hint for multi-tenant |
113
135
 
114
- ### Usar `redirect_uri` y `tenant_hint`
115
- ```typescript
116
- const auth = new BigsoAuth({
117
- clientId: 'abc123',
118
- ssoOrigin: 'https://sso.bigso.co',
119
- jwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
120
- redirectUri: 'https://admin.miapp.com/callback',
121
- tenantHint: 'enterprise'
122
- });
123
- ```
136
+ #### `auth.login()`
124
137
 
125
- ### Manejo de fallback personalizado
126
- Puedes escuchar el evento `fallback` para ejecutar tu propia lógica antes de la redirección automática:
138
+ Returns `Promise<BigsoAuthResult>`:
127
139
 
128
- ```typescript
129
- auth.on('fallback', () => {
130
- console.log('Mostrando spinner o mensaje...');
131
- // Por defecto, el SDK redirige a /authorize.
132
- // Si quieres evitar la redirección automática, puedes sobrescribir el comportamiento
133
- // pero no es recomendable ya que es el mecanismo de último recurso.
134
- });
135
- ```
140
+ | Field | Type | Description |
141
+ |---|---|---|
142
+ | `code` | `string` | Authorization code from SSO |
143
+ | `codeVerifier` | `string` | PKCE code verifier — send to backend |
144
+ | `state` | `string` | Matches your original state |
145
+ | `nonce` | `string` | Matches your original nonce |
146
+ | `signed_payload` | `string` | JWS signed payload |
147
+ | `tenant` | `SsoTenant` | Tenant data (if included) |
136
148
 
137
- ## 🔒 Consideraciones de seguridad
149
+ ### Node: `BigsoSsoClient`
138
150
 
139
- - **Whitelist de origins**: El SDK asume que el SSO Core está configurado correctamente con la whitelist de origins para cada `client_id` y que responde con `Content-Security-Policy: frame-ancestors`. El SDK no puede controlar esto; es responsabilidad del administrador del SSO.
140
- - **Validación en backend**: La verificación del JWS en el frontend es solo una capa adicional de integridad. El backend debe validar la firma, el nonce, el state y canjear el código usando PKCE antes de emitir tokens.
141
- - **nonce y state**: El SDK genera valores aleatorios seguros (`crypto.randomUUID`) y los valida en el frontend. El backend debe realizar la misma validación para prevenir ataques de replay.
142
- - **Prevención de replay**: El SDK no incluye lógica de deduplicación de JWS en el frontend; esto debe implementarse en el backend usando `jti` si es necesario.
143
- - **Timeout**: El timeout se inicia solo después de `sso-ready`, evitando falsos positivos. Si se alcanza, el SDK ejecuta un fallback a redirección (endpoint `/authorize`).
144
- - **Versiones**: El SDK usa `v: '2.3'`. Si el iframe responde con `version_mismatch`, se activa el fallback automático.
151
+ | Method | Description |
152
+ |---|---|
153
+ | `exchangeCode(code, codeVerifier)` | Exchange auth code for tokens via `/api/v2/auth/exchange` |
154
+ | `refreshTokens()` | Refresh tokens via `/api/v2/auth/refresh` (uses cookie) |
155
+ | `logout(accessToken, revokeAll?)` | Revoke session via `/api/v2/auth/logout` |
156
+ | `validateAccessToken(token)` | Verify JWT locally against JWKS |
157
+ | `verifySignedPayload(token, audience)` | Verify JWS signed payload |
145
158
 
146
- ## 🛠️ Desarrollo
159
+ ### Express: `createSsoAuthRouter(options)`
147
160
 
148
- ### Construcción
149
- ```bash
150
- npm run build # genera dist/ con formatos ESM, CJS y types
151
- ```
161
+ | Route | Method | Description |
162
+ |---|---|---|
163
+ | `/exchange` | POST | `{code, codeVerifier}` v2 exchange |
164
+ | `/exchange-v2` | POST | `{payload}` → verify JWS, then v2 exchange |
165
+ | `/session` | GET | Validate Bearer token, return user data |
166
+ | `/refresh` | POST | Proxy to `/api/v2/auth/refresh` |
167
+ | `/logout` | POST | Bearer token → `/api/v2/auth/logout` |
168
+
169
+ ### Express: `ssoAuthMiddleware({ ssoClient })`
170
+
171
+ Reads `Authorization: Bearer <token>`, validates JWT against JWKS, populates `req.user`, `req.tenant`, `req.tokenPayload`.
172
+
173
+ ## Flujo PKCE completo
152
174
 
153
- ### Pruebas
154
- ```bash
155
- npm test # ejecuta vitest
156
175
  ```
176
+ 1. Browser SDK genera: state, nonce, codeVerifier
177
+ 2. Browser SDK computa: codeChallenge = SHA256(codeVerifier)
178
+ 3. Browser SDK → iframe: {codeChallenge, state, nonce}
179
+ 4. Iframe → SSO Core: POST /api/v2/auth/authorize (con codeChallenge)
180
+ 5. Iframe → Browser SDK: {code, state} (firmado como JWS)
181
+ 6. Browser SDK verifica JWS, valida state y nonce
182
+ 7. Browser SDK retorna {code, codeVerifier} al consuming app
183
+ 8. Consuming app → su backend: POST /exchange-v2-pkce {payload, codeVerifier}
184
+ 9. Backend verifica JWS, extrae code, llama /api/v2/auth/exchange {code, appId, codeVerifier}
185
+ 10. SSO Core verifica: SHA256(codeVerifier) === codeChallenge → emite tokens
186
+ ```
187
+
188
+ ## Seguridad
189
+
190
+ - **PKCE**: codeVerifier nunca sale del browser hasta el paso 7, pero jamás se envía al SSO iframe
191
+ - **JWS**: El signed_payload se verifica contra JWKS en frontend y backend
192
+ - **state + nonce**: Validados en ambos lados para prevenir CSRF y replay
193
+ - **JWT Bearer**: Access tokens validados localmente contra JWKS, revocables en Redis/PG
194
+ - **httpOnly cookies**: Refresh tokens via cookie, nunca accesibles via JS
195
+
196
+ ## Desarrollo
157
197
 
158
- ### Linting
159
198
  ```bash
160
- npm run lint
199
+ npm run build # ESM + CJS + types → dist/
200
+ npm run dev # watch mode
201
+ npm run lint # eslint
202
+ npm test # vitest
161
203
  ```
162
204
 
163
- ## 📝 Changelog
205
+ ## Changelog
164
206
 
165
- ### v0.4.0 (2026-03-23)
166
- Protocolo actualizado a SSO v2.3
167
- - Mensaje `sso-init` con `v: '2.3'`.
168
- - Timeout reactivo (se inicia tras `sso-ready`).
169
- - Validación de `requestId` en respuestas.
170
- - Soporte para `redirect_uri`, `tenant_hint`, `timeout_ms`.
171
- - Manejo de error `version_mismatch` con fallback automático.
172
- - Validación de `nonce` en el frontend tras verificar JWS.
207
+ ### v0.5.0 (2026-04-07) — Full v2
173
208
 
174
- **Mejoras internas:**
175
- - Método `abort()` para cancelar operación.
176
- - Evento `debug` opcional.
177
- - Documentación completa.
209
+ **Breaking changes:**
210
+ - All v1 API endpoints removed (`/api/v1/auth/token`, `/api/v1/auth/verify-session`, etc.)
211
+ - `SsoSessionData`, `SsoRefreshData`, `SsoExchangeResponse` types removed
212
+ - `ssoAuthMiddleware` now validates Bearer JWT (no cookies)
213
+ - Express routes use v2 endpoints exclusively
214
+ - `BigsoSsoClient` methods renamed/changed
178
215
 
179
- **Breaking changes:** Ninguno, pero se recomienda actualizar el backend para validar `nonce` si no lo hacía antes.
216
+ **New features:**
217
+ - `BigsoAuthResult.codeVerifier` — PKCE verifier exposed for backend exchange
218
+ - `BigsoSsoClient.exchangeCode(code, codeVerifier)` — PKCE exchange via `/api/v2/auth/exchange`
219
+ - `BigsoSsoClient.refreshTokens()` — via `/api/v2/auth/refresh`
220
+ - `BigsoSsoClient.logout(accessToken)` — via `/api/v2/auth/logout`
221
+ - `BigsoSsoClient.validateAccessToken(token)` — Local JWT verification against JWKS
222
+ - Express `/exchange-v2-pkce` route with full PKCE support
223
+ - Express `/refresh` and `/logout` routes for v2 API
224
+ - `ssoAuthMiddleware` validates Bearer JWT tokens locally
180
225
 
181
- ### v0.2.0 (anterior)
182
- - Implementación inicial con v2.2.
226
+ ### v0.4.0 (2026-03-23)
227
+ - SSO v2.3 protocol support (iframe postMessage)
228
+ - PKCE, JWS verification, nonce validation
229
+ - Timeout reactive (starts after `sso-ready`)
183
230
 
184
- ## 📄 Licencia
185
- MIT © Bigso
231
+ ## Licencia
186
232
 
187
- ## 🤝 Contribuciones
188
- Por favor, abre un issue o pull request en el repositorio oficial.
233
+ MIT © Bigso
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bigso/auth-sdk",
3
- "version": "0.4.7",
4
- "description": "SDK de autenticación para SSO v2.3 con iframe seguro",
3
+ "version": "0.5.1",
4
+ "description": "SDK de autenticación para SSO v2 - JWT Bearer + PKCE",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
7
7
  "access": "public"