@bigso/auth-sdk 0.5.2 → 0.5.4
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 +60 -21
- package/dist/browser/index.cjs +6 -5
- package/dist/browser/index.d.cts +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +7 -6
- package/dist/chunk-PB3GVAEJ.js +33 -0
- package/dist/express/index.cjs +5 -5
- package/dist/express/index.d.cts +1 -1
- package/dist/express/index.d.ts +1 -1
- package/dist/express/index.js +5 -5
- package/dist/node/index.cjs +1 -0
- package/dist/node/index.d.cts +1 -1
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +1 -1
- package/dist/types-K3V5MV8v.d.cts +81 -0
- package/dist/types-K3V5MV8v.d.ts +81 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ SDK oficial de autenticación para Bigso SSO v2. Flujo basado en JWT Bearer toke
|
|
|
10
10
|
- **JWS verification** en frontend con JWKS remoto
|
|
11
11
|
- **3 entry points**: Browser, Node.js, Express middleware
|
|
12
12
|
- **Server-to-server** login, exchange, refresh, logout via API v2
|
|
13
|
+
- **Scope array** en JWT para consumir APIs internas
|
|
13
14
|
|
|
14
15
|
## Instalación
|
|
15
16
|
|
|
@@ -25,15 +26,15 @@ npm install @bigso/auth-sdk
|
|
|
25
26
|
│ (consuming) │ sso-init / sso-success │ (iframe) │
|
|
26
27
|
└──────┬───────┘ └──────┬───────┘
|
|
27
28
|
│ │
|
|
28
|
-
│ 1. auth.login() → codeVerifier
|
|
29
|
-
│ 2. POST /exchange-v2
|
|
30
|
-
│ {
|
|
29
|
+
│ 1. auth.login() → codeVerifier │
|
|
30
|
+
│ 2. POST /api/auth/exchange-v2 │
|
|
31
|
+
│ { payload, codeVerifier } │
|
|
31
32
|
▼ ▼
|
|
32
33
|
┌──────────────┐ POST /api/v2/auth/exchange ┌──────────────┐
|
|
33
34
|
│ App Backend │──────────────────────────────────►│ SSO Core │
|
|
34
35
|
│ (Express) │◄─────────────────────────────────│ (API v2) │
|
|
35
36
|
│ │ { accessToken, refreshToken } │ │
|
|
36
|
-
└──────────────┘
|
|
37
|
+
└──────────────┘ (con scope array) └──────────────┘
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
## Uso
|
|
@@ -44,9 +45,9 @@ npm install @bigso/auth-sdk
|
|
|
44
45
|
import { BigsoAuth } from '@bigso/auth-sdk';
|
|
45
46
|
|
|
46
47
|
const auth = new BigsoAuth({
|
|
47
|
-
clientId: '
|
|
48
|
-
ssoOrigin: 'https://sso.bigso.co',
|
|
49
|
-
jwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
|
|
48
|
+
clientId: 'ordamy',
|
|
49
|
+
ssoOrigin: 'https://sso-portal.bigso.co',
|
|
50
|
+
jwksUrl: 'https://sso-core.bigso.co/.well-known/jwks.json',
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
auth.on('success', async (result) => {
|
|
@@ -57,11 +58,12 @@ auth.on('success', async (result) => {
|
|
|
57
58
|
// result.nonce → matches your original nonce
|
|
58
59
|
|
|
59
60
|
// Send to your backend:
|
|
60
|
-
const response = await fetch('/api/auth/exchange-v2
|
|
61
|
+
const response = await fetch('/api/auth/exchange-v2', {
|
|
61
62
|
method: 'POST',
|
|
62
63
|
headers: { 'Content-Type': 'application/json' },
|
|
63
64
|
body: JSON.stringify({
|
|
64
65
|
payload: result.signed_payload,
|
|
66
|
+
codeVerifier: result.codeVerifier,
|
|
65
67
|
}),
|
|
66
68
|
});
|
|
67
69
|
});
|
|
@@ -76,15 +78,15 @@ import { BigsoSsoClient } from '@bigso/auth-sdk/node';
|
|
|
76
78
|
import { createSsoAuthRouter, ssoAuthMiddleware } from '@bigso/auth-sdk/express';
|
|
77
79
|
|
|
78
80
|
const ssoClient = new BigsoSsoClient({
|
|
79
|
-
ssoBackendUrl: 'https://sso.bigso.co',
|
|
80
|
-
ssoJwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
|
|
81
|
-
appId: '
|
|
81
|
+
ssoBackendUrl: 'https://sso-core.bigso.co',
|
|
82
|
+
ssoJwksUrl: 'https://sso-core.bigso.co/.well-known/jwks.json',
|
|
83
|
+
appId: 'ordamy',
|
|
82
84
|
});
|
|
83
85
|
|
|
84
86
|
// Auth routes: /exchange, /exchange-v2, /session, /refresh, /logout
|
|
85
87
|
app.use('/api/auth', createSsoAuthRouter({
|
|
86
88
|
ssoClient,
|
|
87
|
-
frontendUrl: 'https://
|
|
89
|
+
frontendUrl: 'https://ordamy.bigso.co',
|
|
88
90
|
}));
|
|
89
91
|
|
|
90
92
|
// Protected routes: validates Bearer JWT token
|
|
@@ -99,9 +101,9 @@ app.get('/api/protected', ssoAuthMiddleware({ ssoClient }), (req, res) => {
|
|
|
99
101
|
import { BigsoSsoClient } from '@bigso/auth-sdk/node';
|
|
100
102
|
|
|
101
103
|
const client = new BigsoSsoClient({
|
|
102
|
-
ssoBackendUrl: 'https://sso.bigso.co',
|
|
103
|
-
ssoJwksUrl: 'https://sso.bigso.co/.well-known/jwks.json',
|
|
104
|
-
appId: '
|
|
104
|
+
ssoBackendUrl: 'https://sso-core.bigso.co',
|
|
105
|
+
ssoJwksUrl: 'https://sso-core.bigso.co/.well-known/jwks.json',
|
|
106
|
+
appId: 'ordamy',
|
|
105
107
|
});
|
|
106
108
|
|
|
107
109
|
// Exchange authorization code with PKCE
|
|
@@ -126,7 +128,7 @@ await client.logout('eyJhbG...', true); // revokeAll = true
|
|
|
126
128
|
| Param | Type | Required | Default | Description |
|
|
127
129
|
|---|---|---|---|---|
|
|
128
130
|
| `clientId` | `string` | Yes | — | App ID registered in SSO |
|
|
129
|
-
| `ssoOrigin` | `string` | Yes | — | SSO origin (e.g. `https://sso.bigso.co`) |
|
|
131
|
+
| `ssoOrigin` | `string` | Yes | — | SSO origin (e.g. `https://sso-portal.bigso.co`) |
|
|
130
132
|
| `jwksUrl` | `string` | Yes | — | JWKS URL for JWS verification |
|
|
131
133
|
| `timeout` | `number` | No | `5000` | Timeout after `sso-ready` (ms) |
|
|
132
134
|
| `debug` | `boolean` | No | `false` | Debug logging |
|
|
@@ -161,7 +163,7 @@ Returns `Promise<BigsoAuthResult>`:
|
|
|
161
163
|
| Route | Method | Description |
|
|
162
164
|
|---|---|---|
|
|
163
165
|
| `/exchange` | POST | `{code, codeVerifier}` → v2 exchange |
|
|
164
|
-
| `/exchange-v2` | POST | `{payload}` → verify JWS, then v2 exchange |
|
|
166
|
+
| `/exchange-v2` | POST | `{payload, codeVerifier?}` → verify JWS, then v2 exchange (codeVerifier from body or JWS) |
|
|
165
167
|
| `/session` | GET | Validate Bearer token, return user data |
|
|
166
168
|
| `/refresh` | POST | Proxy to `/api/v2/auth/refresh` |
|
|
167
169
|
| `/logout` | POST | Bearer token → `/api/v2/auth/logout` |
|
|
@@ -177,14 +179,34 @@ Reads `Authorization: Bearer <token>`, validates JWT against JWKS, populates `re
|
|
|
177
179
|
2. Browser SDK computa: codeChallenge = SHA256(codeVerifier)
|
|
178
180
|
3. Browser SDK → iframe: {codeChallenge, state, nonce}
|
|
179
181
|
4. Iframe → SSO Core: POST /api/v2/auth/authorize (con codeChallenge)
|
|
180
|
-
5. Iframe → Browser SDK: {code,
|
|
182
|
+
5. Iframe → Browser SDK: {code, signedPayload} (JWS contiene code_verifier si se pasó)
|
|
181
183
|
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
|
|
184
|
+
7. Browser SDK retorna {code, codeVerifier, signed_payload} al consuming app
|
|
185
|
+
8. Consuming app → su backend: POST /exchange-v2 {payload, codeVerifier}
|
|
184
186
|
9. Backend verifica JWS, extrae code, llama /api/v2/auth/exchange {code, appId, codeVerifier}
|
|
185
187
|
10. SSO Core verifica: SHA256(codeVerifier) === codeChallenge → emite tokens
|
|
186
188
|
```
|
|
187
189
|
|
|
190
|
+
## JWT Access Token
|
|
191
|
+
|
|
192
|
+
El access token contiene:
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"sub": "user-uuid",
|
|
197
|
+
"jti": "token-uuid",
|
|
198
|
+
"iss": "https://sso.bigso.co",
|
|
199
|
+
"aud": "https://ordamy.bigso.co",
|
|
200
|
+
"exp": 1234567890,
|
|
201
|
+
"iat": 1234567890,
|
|
202
|
+
"tenants": [{ "id": "...", "name": "...", "slug": "...", "role": "...", "apps": ["ordamy"] }],
|
|
203
|
+
"systemRole": "user",
|
|
204
|
+
"scope": ["https://ordamy.bigso.co", "https://api-interna.bigso.co"]
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
El campo `scope` define qué APIs puede consumir este token. Cada aplicación tiene su `scope` configurado en la BD de SSO Core.
|
|
209
|
+
|
|
188
210
|
## Seguridad
|
|
189
211
|
|
|
190
212
|
- **PKCE**: codeVerifier nunca sale del browser hasta el paso 7, pero jamás se envía al SSO iframe
|
|
@@ -192,6 +214,7 @@ Reads `Authorization: Bearer <token>`, validates JWT against JWKS, populates `re
|
|
|
192
214
|
- **state + nonce**: Validados en ambos lados para prevenir CSRF y replay
|
|
193
215
|
- **JWT Bearer**: Access tokens validados localmente contra JWKS, revocables en Redis/PG
|
|
194
216
|
- **httpOnly cookies**: Refresh tokens via cookie, nunca accesibles via JS
|
|
217
|
+
- **Scope validation**: APIs internas deben verificar que su URL esté en el array `scope` del token
|
|
195
218
|
|
|
196
219
|
## Desarrollo
|
|
197
220
|
|
|
@@ -204,6 +227,22 @@ npm test # vitest
|
|
|
204
227
|
|
|
205
228
|
## Changelog
|
|
206
229
|
|
|
230
|
+
### v0.5.3 (2026-04-09)
|
|
231
|
+
|
|
232
|
+
- `exchange-v2` ahora acepta `codeVerifier` del body del request o del JWS (antes solo del JWS)
|
|
233
|
+
- Fix de fallback: `buildFallbackUrl()` ahora incluye `code_challenge` en la URL
|
|
234
|
+
|
|
235
|
+
### v0.5.2 (2026-04-08)
|
|
236
|
+
|
|
237
|
+
- Nuevo campo `scope?: string[]` en `SsoTokenPayload`
|
|
238
|
+
- `verifyAccessToken()` mapea `scope` del JWT payload
|
|
239
|
+
- `prepublishOnly` script agregado para build automático antes de publish
|
|
240
|
+
|
|
241
|
+
### v0.5.1 (2026-04-08)
|
|
242
|
+
|
|
243
|
+
- Fix: SDK sin dist/ — `prepublishOnly: "npm run build"` agregado
|
|
244
|
+
- `SsoJwtTenant` con `apps: string[]`
|
|
245
|
+
|
|
207
246
|
### v0.5.0 (2026-04-07) — Full v2
|
|
208
247
|
|
|
209
248
|
**Breaking changes:**
|
|
@@ -219,7 +258,7 @@ npm test # vitest
|
|
|
219
258
|
- `BigsoSsoClient.refreshTokens()` — via `/api/v2/auth/refresh`
|
|
220
259
|
- `BigsoSsoClient.logout(accessToken)` — via `/api/v2/auth/logout`
|
|
221
260
|
- `BigsoSsoClient.validateAccessToken(token)` — Local JWT verification against JWKS
|
|
222
|
-
- Express `/exchange-v2
|
|
261
|
+
- Express `/exchange-v2` route with full PKCE support
|
|
223
262
|
- Express `/refresh` and `/logout` routes for v2 API
|
|
224
263
|
- `ssoAuthMiddleware` validates Bearer JWT tokens locally
|
|
225
264
|
|
package/dist/browser/index.cjs
CHANGED
|
@@ -98,6 +98,7 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
98
98
|
const nonce = generateRandomId();
|
|
99
99
|
const verifier = generateVerifier();
|
|
100
100
|
const requestId = this.requestId;
|
|
101
|
+
const codeChallenge = await sha256Base64Url(verifier);
|
|
101
102
|
sessionStorage.setItem("sso_ctx", JSON.stringify({ state, nonce, verifier, requestId }));
|
|
102
103
|
this.createUI();
|
|
103
104
|
return new Promise((resolve, reject) => {
|
|
@@ -130,11 +131,10 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
130
131
|
this.closeUI();
|
|
131
132
|
cleanup();
|
|
132
133
|
this.emit("fallback");
|
|
133
|
-
window.location.href = this.buildFallbackUrl();
|
|
134
|
+
window.location.href = this.buildFallbackUrl(codeChallenge, state);
|
|
134
135
|
reject(new Error("Timeout"));
|
|
135
136
|
}
|
|
136
137
|
}, this.options.timeout);
|
|
137
|
-
const codeChallenge = await sha256Base64Url(verifier);
|
|
138
138
|
const initPayload = {
|
|
139
139
|
state,
|
|
140
140
|
nonce,
|
|
@@ -207,7 +207,7 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
207
207
|
cleanup();
|
|
208
208
|
if (errorPayload.code === "version_mismatch") {
|
|
209
209
|
this.emit("error", errorPayload);
|
|
210
|
-
window.location.href = this.buildFallbackUrl();
|
|
210
|
+
window.location.href = this.buildFallbackUrl(codeChallenge, state);
|
|
211
211
|
reject(new Error(`Version mismatch: expected ${errorPayload.expected_version}`));
|
|
212
212
|
} else {
|
|
213
213
|
this.emit("error", errorPayload);
|
|
@@ -342,12 +342,13 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
342
342
|
`;
|
|
343
343
|
}
|
|
344
344
|
// ─── Helpers ──────────────────────────────────────────────────────
|
|
345
|
-
buildFallbackUrl() {
|
|
345
|
+
buildFallbackUrl(codeChallenge, state) {
|
|
346
346
|
const url = new URL(this.options.ssoOrigin);
|
|
347
347
|
url.searchParams.set("app_id", this.options.clientId);
|
|
348
348
|
url.searchParams.set("redirect_uri", this.options.redirectUri || window.location.origin);
|
|
349
349
|
url.searchParams.set("response_type", "code");
|
|
350
|
-
url.searchParams.set("state",
|
|
350
|
+
url.searchParams.set("state", state);
|
|
351
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
351
352
|
url.searchParams.set("code_challenge_method", "S256");
|
|
352
353
|
url.searchParams.set("client_id", this.options.clientId);
|
|
353
354
|
return url.toString();
|
package/dist/browser/index.d.cts
CHANGED
package/dist/browser/index.d.ts
CHANGED
package/dist/browser/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
verifySignedPayload
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-PB3GVAEJ.js";
|
|
4
4
|
|
|
5
5
|
// src/utils/crypto.ts
|
|
6
6
|
async function sha256Base64Url(input) {
|
|
@@ -66,6 +66,7 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
66
66
|
const nonce = generateRandomId();
|
|
67
67
|
const verifier = generateVerifier();
|
|
68
68
|
const requestId = this.requestId;
|
|
69
|
+
const codeChallenge = await sha256Base64Url(verifier);
|
|
69
70
|
sessionStorage.setItem("sso_ctx", JSON.stringify({ state, nonce, verifier, requestId }));
|
|
70
71
|
this.createUI();
|
|
71
72
|
return new Promise((resolve, reject) => {
|
|
@@ -98,11 +99,10 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
98
99
|
this.closeUI();
|
|
99
100
|
cleanup();
|
|
100
101
|
this.emit("fallback");
|
|
101
|
-
window.location.href = this.buildFallbackUrl();
|
|
102
|
+
window.location.href = this.buildFallbackUrl(codeChallenge, state);
|
|
102
103
|
reject(new Error("Timeout"));
|
|
103
104
|
}
|
|
104
105
|
}, this.options.timeout);
|
|
105
|
-
const codeChallenge = await sha256Base64Url(verifier);
|
|
106
106
|
const initPayload = {
|
|
107
107
|
state,
|
|
108
108
|
nonce,
|
|
@@ -175,7 +175,7 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
175
175
|
cleanup();
|
|
176
176
|
if (errorPayload.code === "version_mismatch") {
|
|
177
177
|
this.emit("error", errorPayload);
|
|
178
|
-
window.location.href = this.buildFallbackUrl();
|
|
178
|
+
window.location.href = this.buildFallbackUrl(codeChallenge, state);
|
|
179
179
|
reject(new Error(`Version mismatch: expected ${errorPayload.expected_version}`));
|
|
180
180
|
} else {
|
|
181
181
|
this.emit("error", errorPayload);
|
|
@@ -310,12 +310,13 @@ var BigsoAuth = class extends EventEmitter {
|
|
|
310
310
|
`;
|
|
311
311
|
}
|
|
312
312
|
// ─── Helpers ──────────────────────────────────────────────────────
|
|
313
|
-
buildFallbackUrl() {
|
|
313
|
+
buildFallbackUrl(codeChallenge, state) {
|
|
314
314
|
const url = new URL(this.options.ssoOrigin);
|
|
315
315
|
url.searchParams.set("app_id", this.options.clientId);
|
|
316
316
|
url.searchParams.set("redirect_uri", this.options.redirectUri || window.location.origin);
|
|
317
317
|
url.searchParams.set("response_type", "code");
|
|
318
|
-
url.searchParams.set("state",
|
|
318
|
+
url.searchParams.set("state", state);
|
|
319
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
319
320
|
url.searchParams.set("code_challenge_method", "S256");
|
|
320
321
|
url.searchParams.set("client_id", this.options.clientId);
|
|
321
322
|
return url.toString();
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/utils/jws.ts
|
|
2
|
+
import { jwtVerify, createRemoteJWKSet } from "jose";
|
|
3
|
+
async function verifySignedPayload(token, jwksUrl, expectedAudience) {
|
|
4
|
+
const JWKS = createRemoteJWKSet(new URL(jwksUrl));
|
|
5
|
+
const { payload } = await jwtVerify(token, JWKS, {
|
|
6
|
+
audience: expectedAudience
|
|
7
|
+
});
|
|
8
|
+
return payload;
|
|
9
|
+
}
|
|
10
|
+
async function verifyAccessToken(accessToken, jwksUrl) {
|
|
11
|
+
const JWKS = createRemoteJWKSet(new URL(jwksUrl));
|
|
12
|
+
const { payload } = await jwtVerify(accessToken, JWKS);
|
|
13
|
+
if (!payload.sub || !payload.jti) {
|
|
14
|
+
throw new Error("Invalid token structure: missing sub or jti");
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
sub: payload.sub,
|
|
18
|
+
jti: payload.jti,
|
|
19
|
+
iss: payload.iss,
|
|
20
|
+
aud: payload.aud || "",
|
|
21
|
+
exp: payload.exp,
|
|
22
|
+
iat: payload.iat,
|
|
23
|
+
tenants: payload.tenants || [],
|
|
24
|
+
systemRole: payload.systemRole || "user",
|
|
25
|
+
scope: payload.scope,
|
|
26
|
+
deviceFingerprint: payload.deviceFingerprint
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
verifySignedPayload,
|
|
32
|
+
verifyAccessToken
|
|
33
|
+
};
|
package/dist/express/index.cjs
CHANGED
|
@@ -122,7 +122,7 @@ function createSsoAuthRouter(options) {
|
|
|
122
122
|
});
|
|
123
123
|
router.post("/exchange-v2", async (req, res) => {
|
|
124
124
|
try {
|
|
125
|
-
const { payload } = req.body;
|
|
125
|
+
const { payload, codeVerifier: codeVerifierFromBody } = req.body;
|
|
126
126
|
if (!payload) {
|
|
127
127
|
res.status(400).json({ error: "Signed payload is required" });
|
|
128
128
|
return;
|
|
@@ -132,12 +132,12 @@ function createSsoAuthRouter(options) {
|
|
|
132
132
|
res.status(400).json({ error: "No authorization code found in payload" });
|
|
133
133
|
return;
|
|
134
134
|
}
|
|
135
|
-
const
|
|
136
|
-
if (!
|
|
137
|
-
res.status(400).json({ error: "
|
|
135
|
+
const verifier = codeVerifierFromBody || verified.code_verifier;
|
|
136
|
+
if (!verifier) {
|
|
137
|
+
res.status(400).json({ error: "codeVerifier is required for PKCE exchange" });
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
|
-
const ssoResponse = await options.ssoClient.exchangeCode(verified.code,
|
|
140
|
+
const ssoResponse = await options.ssoClient.exchangeCode(verified.code, verifier);
|
|
141
141
|
if (options.onLoginSuccess) {
|
|
142
142
|
await options.onLoginSuccess(ssoResponse);
|
|
143
143
|
}
|
package/dist/express/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Request, Response, NextFunction, Router } from 'express';
|
|
2
2
|
import { BigsoSsoClient } from '../node/index.cjs';
|
|
3
|
-
import { S as SsoJwtTenant, b as SsoTokenPayload, V as V2ExchangeResponse } from '../types-
|
|
3
|
+
import { S as SsoJwtTenant, b as SsoTokenPayload, V as V2ExchangeResponse } from '../types-K3V5MV8v.cjs';
|
|
4
4
|
|
|
5
5
|
interface SsoAuthMiddlewareOptions {
|
|
6
6
|
ssoClient: BigsoSsoClient;
|
package/dist/express/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Request, Response, NextFunction, Router } from 'express';
|
|
2
2
|
import { BigsoSsoClient } from '../node/index.js';
|
|
3
|
-
import { S as SsoJwtTenant, b as SsoTokenPayload, V as V2ExchangeResponse } from '../types-
|
|
3
|
+
import { S as SsoJwtTenant, b as SsoTokenPayload, V as V2ExchangeResponse } from '../types-K3V5MV8v.js';
|
|
4
4
|
|
|
5
5
|
interface SsoAuthMiddlewareOptions {
|
|
6
6
|
ssoClient: BigsoSsoClient;
|
package/dist/express/index.js
CHANGED
|
@@ -93,7 +93,7 @@ function createSsoAuthRouter(options) {
|
|
|
93
93
|
});
|
|
94
94
|
router.post("/exchange-v2", async (req, res) => {
|
|
95
95
|
try {
|
|
96
|
-
const { payload } = req.body;
|
|
96
|
+
const { payload, codeVerifier: codeVerifierFromBody } = req.body;
|
|
97
97
|
if (!payload) {
|
|
98
98
|
res.status(400).json({ error: "Signed payload is required" });
|
|
99
99
|
return;
|
|
@@ -103,12 +103,12 @@ function createSsoAuthRouter(options) {
|
|
|
103
103
|
res.status(400).json({ error: "No authorization code found in payload" });
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
|
-
const
|
|
107
|
-
if (!
|
|
108
|
-
res.status(400).json({ error: "
|
|
106
|
+
const verifier = codeVerifierFromBody || verified.code_verifier;
|
|
107
|
+
if (!verifier) {
|
|
108
|
+
res.status(400).json({ error: "codeVerifier is required for PKCE exchange" });
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
|
-
const ssoResponse = await options.ssoClient.exchangeCode(verified.code,
|
|
111
|
+
const ssoResponse = await options.ssoClient.exchangeCode(verified.code, verifier);
|
|
112
112
|
if (options.onLoginSuccess) {
|
|
113
113
|
await options.onLoginSuccess(ssoResponse);
|
|
114
114
|
}
|
package/dist/node/index.cjs
CHANGED
package/dist/node/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as SsoTokenPayload, c as V2LoginResponse, V as V2ExchangeResponse, d as V2RefreshResponse } from '../types-
|
|
1
|
+
import { b as SsoTokenPayload, c as V2LoginResponse, V as V2ExchangeResponse, d as V2RefreshResponse } from '../types-K3V5MV8v.cjs';
|
|
2
2
|
|
|
3
3
|
interface SsoClientOptions {
|
|
4
4
|
ssoBackendUrl: string;
|
package/dist/node/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as SsoTokenPayload, c as V2LoginResponse, V as V2ExchangeResponse, d as V2RefreshResponse } from '../types-
|
|
1
|
+
import { b as SsoTokenPayload, c as V2LoginResponse, V as V2ExchangeResponse, d as V2RefreshResponse } from '../types-K3V5MV8v.js';
|
|
2
2
|
|
|
3
3
|
interface SsoClientOptions {
|
|
4
4
|
ssoBackendUrl: string;
|
package/dist/node/index.js
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
interface BigsoAuthOptions {
|
|
2
|
+
clientId: string;
|
|
3
|
+
ssoOrigin: string;
|
|
4
|
+
jwksUrl: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
debug?: boolean;
|
|
7
|
+
redirectUri?: string;
|
|
8
|
+
tenantHint?: string;
|
|
9
|
+
theme?: 'light' | 'dark';
|
|
10
|
+
}
|
|
11
|
+
interface SsoUser {
|
|
12
|
+
userId: string;
|
|
13
|
+
email: string;
|
|
14
|
+
firstName: string;
|
|
15
|
+
lastName: string;
|
|
16
|
+
}
|
|
17
|
+
interface SsoTenant {
|
|
18
|
+
tenantId: string;
|
|
19
|
+
name: string;
|
|
20
|
+
slug: string;
|
|
21
|
+
role: string;
|
|
22
|
+
}
|
|
23
|
+
interface SsoJwtTenant {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
role: string;
|
|
28
|
+
apps: string[];
|
|
29
|
+
}
|
|
30
|
+
interface SsoTokenPayload {
|
|
31
|
+
sub: string;
|
|
32
|
+
jti: string;
|
|
33
|
+
iss: string;
|
|
34
|
+
aud: string;
|
|
35
|
+
exp: number;
|
|
36
|
+
iat: number;
|
|
37
|
+
tenants: SsoJwtTenant[];
|
|
38
|
+
systemRole: string;
|
|
39
|
+
scope?: string[];
|
|
40
|
+
deviceFingerprint?: string;
|
|
41
|
+
}
|
|
42
|
+
interface V2LoginResponse {
|
|
43
|
+
success: boolean;
|
|
44
|
+
tokens: {
|
|
45
|
+
accessToken: string;
|
|
46
|
+
expiresIn: number;
|
|
47
|
+
};
|
|
48
|
+
user: SsoUser;
|
|
49
|
+
}
|
|
50
|
+
interface V2ExchangeResponse {
|
|
51
|
+
success: boolean;
|
|
52
|
+
tokens: {
|
|
53
|
+
accessToken: string;
|
|
54
|
+
refreshToken: string;
|
|
55
|
+
expiresIn: number;
|
|
56
|
+
};
|
|
57
|
+
user: SsoUser;
|
|
58
|
+
tenant: SsoTenant;
|
|
59
|
+
}
|
|
60
|
+
interface V2RefreshResponse {
|
|
61
|
+
success: boolean;
|
|
62
|
+
tokens: {
|
|
63
|
+
accessToken: string;
|
|
64
|
+
expiresIn: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
interface BigsoAuthResult {
|
|
68
|
+
code: string;
|
|
69
|
+
state: string;
|
|
70
|
+
nonce: string;
|
|
71
|
+
codeVerifier: string;
|
|
72
|
+
signed_payload: string;
|
|
73
|
+
tenant?: SsoTenant;
|
|
74
|
+
jti?: string;
|
|
75
|
+
iss?: string;
|
|
76
|
+
aud?: string;
|
|
77
|
+
exp?: number;
|
|
78
|
+
iat?: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type { BigsoAuthOptions as B, SsoJwtTenant as S, V2ExchangeResponse as V, BigsoAuthResult as a, SsoTokenPayload as b, V2LoginResponse as c, V2RefreshResponse as d };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
interface BigsoAuthOptions {
|
|
2
|
+
clientId: string;
|
|
3
|
+
ssoOrigin: string;
|
|
4
|
+
jwksUrl: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
debug?: boolean;
|
|
7
|
+
redirectUri?: string;
|
|
8
|
+
tenantHint?: string;
|
|
9
|
+
theme?: 'light' | 'dark';
|
|
10
|
+
}
|
|
11
|
+
interface SsoUser {
|
|
12
|
+
userId: string;
|
|
13
|
+
email: string;
|
|
14
|
+
firstName: string;
|
|
15
|
+
lastName: string;
|
|
16
|
+
}
|
|
17
|
+
interface SsoTenant {
|
|
18
|
+
tenantId: string;
|
|
19
|
+
name: string;
|
|
20
|
+
slug: string;
|
|
21
|
+
role: string;
|
|
22
|
+
}
|
|
23
|
+
interface SsoJwtTenant {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
role: string;
|
|
28
|
+
apps: string[];
|
|
29
|
+
}
|
|
30
|
+
interface SsoTokenPayload {
|
|
31
|
+
sub: string;
|
|
32
|
+
jti: string;
|
|
33
|
+
iss: string;
|
|
34
|
+
aud: string;
|
|
35
|
+
exp: number;
|
|
36
|
+
iat: number;
|
|
37
|
+
tenants: SsoJwtTenant[];
|
|
38
|
+
systemRole: string;
|
|
39
|
+
scope?: string[];
|
|
40
|
+
deviceFingerprint?: string;
|
|
41
|
+
}
|
|
42
|
+
interface V2LoginResponse {
|
|
43
|
+
success: boolean;
|
|
44
|
+
tokens: {
|
|
45
|
+
accessToken: string;
|
|
46
|
+
expiresIn: number;
|
|
47
|
+
};
|
|
48
|
+
user: SsoUser;
|
|
49
|
+
}
|
|
50
|
+
interface V2ExchangeResponse {
|
|
51
|
+
success: boolean;
|
|
52
|
+
tokens: {
|
|
53
|
+
accessToken: string;
|
|
54
|
+
refreshToken: string;
|
|
55
|
+
expiresIn: number;
|
|
56
|
+
};
|
|
57
|
+
user: SsoUser;
|
|
58
|
+
tenant: SsoTenant;
|
|
59
|
+
}
|
|
60
|
+
interface V2RefreshResponse {
|
|
61
|
+
success: boolean;
|
|
62
|
+
tokens: {
|
|
63
|
+
accessToken: string;
|
|
64
|
+
expiresIn: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
interface BigsoAuthResult {
|
|
68
|
+
code: string;
|
|
69
|
+
state: string;
|
|
70
|
+
nonce: string;
|
|
71
|
+
codeVerifier: string;
|
|
72
|
+
signed_payload: string;
|
|
73
|
+
tenant?: SsoTenant;
|
|
74
|
+
jti?: string;
|
|
75
|
+
iss?: string;
|
|
76
|
+
aud?: string;
|
|
77
|
+
exp?: number;
|
|
78
|
+
iat?: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type { BigsoAuthOptions as B, SsoJwtTenant as S, V2ExchangeResponse as V, BigsoAuthResult as a, SsoTokenPayload as b, V2LoginResponse as c, V2RefreshResponse as d };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bigso/auth-sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "SDK de autenticación para SSO v2 - JWT Bearer + PKCE",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsup src/browser/index.ts src/node/index.ts src/express/index.ts --format esm,cjs --dts --out-dir dist",
|
|
40
40
|
"dev": "tsup src/browser/index.ts src/node/index.ts src/express/index.ts --watch --out-dir dist",
|
|
41
|
+
"prepublishOnly": "npm run build",
|
|
41
42
|
"lint": "eslint .",
|
|
42
43
|
"test": "vitest",
|
|
43
44
|
"release": "git tag v$npm_package_version && git push origin v$npm_package_version"
|