@baseworks/auth 0.2.1 → 0.2.3
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/dist/{chunk-NBKMWUCN.js → chunk-5W4TEXCT.js} +7 -8
- package/dist/{chunk-TXDBQMTY.js → chunk-OD5XLL3O.js} +19 -0
- package/dist/edge.js +4 -15
- package/dist/hono.js +1 -1
- package/dist/index.js +3 -3
- package/dist/jwt.d.ts +5 -1
- package/dist/jwt.js +5 -1
- package/dist/session.js +2 -1
- package/package.json +2 -2
- package/src/edge.ts +1 -1
- package/src/jwt.ts +21 -0
- package/src/session.ts +5 -8
- package/src/_internal.ts +0 -14
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseJwtPayload
|
|
3
|
+
} from "./chunk-OD5XLL3O.js";
|
|
1
4
|
import {
|
|
2
5
|
generatePkce
|
|
3
6
|
} from "./chunk-34E5PYNA.js";
|
|
@@ -69,10 +72,6 @@ async function discoverOidc() {
|
|
|
69
72
|
if (!response.ok) throw new Error(`Failed to load OIDC discovery document from ${issuer}.`);
|
|
70
73
|
return await response.json();
|
|
71
74
|
}
|
|
72
|
-
function parseJwtPayload(token) {
|
|
73
|
-
const part = token.split(".")[1] ?? "";
|
|
74
|
-
return JSON.parse(base64urlDecodeString(part));
|
|
75
|
-
}
|
|
76
75
|
function encodeSessionCookie(session) {
|
|
77
76
|
return base64urlEncode(new TextEncoder().encode(JSON.stringify(session)));
|
|
78
77
|
}
|
|
@@ -187,7 +186,7 @@ function sessionFromPayload(payload) {
|
|
|
187
186
|
}
|
|
188
187
|
function applyTokenCookies(response, request, tokens) {
|
|
189
188
|
const options = getCookieOptions(request);
|
|
190
|
-
const payload = parseJwtPayload(tokens.id_token);
|
|
189
|
+
const payload = parseJwtPayload(tokens.id_token) ?? {};
|
|
191
190
|
const expiresAt = payload.exp ?? (tokens.expires_in ? Math.floor(Date.now() / 1e3) + tokens.expires_in : void 0);
|
|
192
191
|
if (!expiresAt) throw new Error("The OIDC ID token did not include an expiry.");
|
|
193
192
|
response.cookies.set(oidcCookies.idToken, tokens.id_token, {
|
|
@@ -268,7 +267,7 @@ async function handleAuthorizationCallback(request) {
|
|
|
268
267
|
redirectUri: getRedirectUri(request),
|
|
269
268
|
tokenEndpoint: discovery.token_endpoint
|
|
270
269
|
});
|
|
271
|
-
const payload = parseJwtPayload(tokens.id_token);
|
|
270
|
+
const payload = parseJwtPayload(tokens.id_token) ?? {};
|
|
272
271
|
if (savedNonce && payload.nonce && payload.nonce !== savedNonce) {
|
|
273
272
|
throw new Error("OIDC nonce mismatch.");
|
|
274
273
|
}
|
|
@@ -289,7 +288,7 @@ async function getSessionFromCookies() {
|
|
|
289
288
|
const idToken = cookieStore.get(oidcCookies.idToken)?.value;
|
|
290
289
|
if (idToken) {
|
|
291
290
|
try {
|
|
292
|
-
return sessionFromPayload(parseJwtPayload(idToken));
|
|
291
|
+
return sessionFromPayload(parseJwtPayload(idToken) ?? {});
|
|
293
292
|
} catch {
|
|
294
293
|
}
|
|
295
294
|
}
|
|
@@ -336,7 +335,7 @@ async function buildSessionResponse(_request) {
|
|
|
336
335
|
status: 401
|
|
337
336
|
});
|
|
338
337
|
}
|
|
339
|
-
return NextResponse.json(sessionFromPayload({ ...parseJwtPayload(idToken), exp: expiresAt }));
|
|
338
|
+
return NextResponse.json(sessionFromPayload({ ...parseJwtPayload(idToken) ?? {}, exp: expiresAt }));
|
|
340
339
|
}
|
|
341
340
|
async function buildTokenResponse(request) {
|
|
342
341
|
const cookieStore = await cookies();
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
// src/jwt.ts
|
|
2
2
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
3
|
+
import { base64urlDecodeString } from "@baseworks/core";
|
|
4
|
+
function parseJwtPayload(token) {
|
|
5
|
+
try {
|
|
6
|
+
const part = token.split(".")[1];
|
|
7
|
+
if (!part) return null;
|
|
8
|
+
return JSON.parse(base64urlDecodeString(part));
|
|
9
|
+
} catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function signHs256Jwt(claims, secret, expiresInSeconds = 86400) {
|
|
14
|
+
const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
|
|
15
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
16
|
+
const payload = Buffer.from(JSON.stringify({ iat: now, exp: now + expiresInSeconds, ...claims })).toString("base64url");
|
|
17
|
+
const sig = createHmac("sha256", secret).update(`${header}.${payload}`).digest("base64url");
|
|
18
|
+
return `${header}.${payload}.${sig}`;
|
|
19
|
+
}
|
|
3
20
|
function verifyHs256Jwt(token, secret) {
|
|
4
21
|
const parts = token.split(".");
|
|
5
22
|
if (parts.length !== 3) return null;
|
|
@@ -19,5 +36,7 @@ function verifyHs256Jwt(token, secret) {
|
|
|
19
36
|
}
|
|
20
37
|
|
|
21
38
|
export {
|
|
39
|
+
parseJwtPayload,
|
|
40
|
+
signHs256Jwt,
|
|
22
41
|
verifyHs256Jwt
|
|
23
42
|
};
|
package/dist/edge.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSessionFromCookies
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5W4TEXCT.js";
|
|
4
|
+
import {
|
|
5
|
+
parseJwtPayload
|
|
6
|
+
} from "./chunk-OD5XLL3O.js";
|
|
4
7
|
import "./chunk-34E5PYNA.js";
|
|
5
8
|
import {
|
|
6
9
|
buildPublicUrl,
|
|
@@ -10,20 +13,6 @@ import {
|
|
|
10
13
|
// src/edge.ts
|
|
11
14
|
import { headers } from "next/headers";
|
|
12
15
|
import { redirect } from "next/navigation";
|
|
13
|
-
|
|
14
|
-
// src/_internal.ts
|
|
15
|
-
import { base64urlDecodeString } from "@baseworks/core";
|
|
16
|
-
function parseJwtPayload(token) {
|
|
17
|
-
try {
|
|
18
|
-
const part = token.split(".")[1];
|
|
19
|
-
if (!part) return null;
|
|
20
|
-
return JSON.parse(base64urlDecodeString(part));
|
|
21
|
-
} catch {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// src/edge.ts
|
|
27
16
|
function firstHeader(headerStore, names) {
|
|
28
17
|
for (const name of names) {
|
|
29
18
|
const value = headerStore.get(name);
|
package/dist/hono.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
verifyHs256Jwt
|
|
3
|
-
} from "./chunk-TXDBQMTY.js";
|
|
4
1
|
import {
|
|
5
2
|
createOidcHumanResolver
|
|
6
3
|
} from "./chunk-6TUNNS2B.js";
|
|
@@ -16,6 +13,9 @@ import {
|
|
|
16
13
|
looksLikeJwt,
|
|
17
14
|
stripBearer
|
|
18
15
|
} from "./chunk-VBIQJKUU.js";
|
|
16
|
+
import {
|
|
17
|
+
verifyHs256Jwt
|
|
18
|
+
} from "./chunk-OD5XLL3O.js";
|
|
19
19
|
import {
|
|
20
20
|
buildOidcAuthUrl,
|
|
21
21
|
generatePkce
|
package/dist/jwt.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Decode a JWT payload without signature verification. Returns null on malformed input. */
|
|
2
|
+
declare function parseJwtPayload(token: string): Record<string, unknown> | null;
|
|
1
3
|
interface JwtClaims {
|
|
2
4
|
sub?: string;
|
|
3
5
|
exp?: number;
|
|
@@ -7,6 +9,8 @@ interface JwtClaims {
|
|
|
7
9
|
type?: string;
|
|
8
10
|
[key: string]: unknown;
|
|
9
11
|
}
|
|
12
|
+
/** Sign an HS256 JWT. Runtime: Node.js only. */
|
|
13
|
+
declare function signHs256Jwt(claims: JwtClaims, secret: string, expiresInSeconds?: number): string;
|
|
10
14
|
/**
|
|
11
15
|
* Verify an HS256 JWT using Node.js crypto.
|
|
12
16
|
* Returns decoded claims on success, null on any failure.
|
|
@@ -14,4 +18,4 @@ interface JwtClaims {
|
|
|
14
18
|
*/
|
|
15
19
|
declare function verifyHs256Jwt(token: string, secret: string): JwtClaims | null;
|
|
16
20
|
|
|
17
|
-
export { type JwtClaims, verifyHs256Jwt };
|
|
21
|
+
export { type JwtClaims, parseJwtPayload, signHs256Jwt, verifyHs256Jwt };
|
package/dist/jwt.js
CHANGED
package/dist/session.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baseworks/auth",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"typecheck": "tsc --noEmit"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@baseworks/core": "
|
|
27
|
+
"@baseworks/core": "^0.2.1",
|
|
28
28
|
"jose": "^6.2.3"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
package/src/edge.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { headers } from "next/headers";
|
|
|
5
5
|
import { redirect } from "next/navigation";
|
|
6
6
|
import { getSessionFromCookies, type OidcSession } from "./session";
|
|
7
7
|
import { buildPublicUrl, normalizeUrlLike } from "./url-helpers";
|
|
8
|
-
import { parseJwtPayload } from "./
|
|
8
|
+
import { parseJwtPayload } from "./jwt.js";
|
|
9
9
|
|
|
10
10
|
export type EdgeAuthProvider = "anonymous" | "cookie" | "pomerium";
|
|
11
11
|
|
package/src/jwt.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import { createHmac, timingSafeEqual } from 'crypto'
|
|
2
|
+
import { base64urlDecodeString } from '@baseworks/core'
|
|
3
|
+
|
|
4
|
+
/** Decode a JWT payload without signature verification. Returns null on malformed input. */
|
|
5
|
+
export function parseJwtPayload(token: string): Record<string, unknown> | null {
|
|
6
|
+
try {
|
|
7
|
+
const part = token.split('.')[1]
|
|
8
|
+
if (!part) return null
|
|
9
|
+
return JSON.parse(base64urlDecodeString(part)) as Record<string, unknown>
|
|
10
|
+
} catch {
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
}
|
|
2
14
|
|
|
3
15
|
export interface JwtClaims {
|
|
4
16
|
sub?: string
|
|
@@ -10,6 +22,15 @@ export interface JwtClaims {
|
|
|
10
22
|
[key: string]: unknown
|
|
11
23
|
}
|
|
12
24
|
|
|
25
|
+
/** Sign an HS256 JWT. Runtime: Node.js only. */
|
|
26
|
+
export function signHs256Jwt(claims: JwtClaims, secret: string, expiresInSeconds = 86400): string {
|
|
27
|
+
const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url')
|
|
28
|
+
const now = Math.floor(Date.now() / 1000)
|
|
29
|
+
const payload = Buffer.from(JSON.stringify({ iat: now, exp: now + expiresInSeconds, ...claims })).toString('base64url')
|
|
30
|
+
const sig = createHmac('sha256', secret).update(`${header}.${payload}`).digest('base64url')
|
|
31
|
+
return `${header}.${payload}.${sig}`
|
|
32
|
+
}
|
|
33
|
+
|
|
13
34
|
/**
|
|
14
35
|
* Verify an HS256 JWT using Node.js crypto.
|
|
15
36
|
* Returns decoded claims on success, null on any failure.
|
package/src/session.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { NextResponse } from "next/server";
|
|
|
7
7
|
import { base64urlEncode, base64urlDecodeString } from "@baseworks/core";
|
|
8
8
|
import { getAuthPublicUrl, normalizeUrlLike } from "./url-helpers";
|
|
9
9
|
import { generatePkce } from "./pkce.js";
|
|
10
|
+
import { parseJwtPayload } from "./jwt.js";
|
|
10
11
|
|
|
11
12
|
type DiscoveryDocument = {
|
|
12
13
|
authorization_endpoint: string;
|
|
@@ -130,10 +131,6 @@ async function discoverOidc() {
|
|
|
130
131
|
return (await response.json()) as DiscoveryDocument;
|
|
131
132
|
}
|
|
132
133
|
|
|
133
|
-
function parseJwtPayload(token: string): JwtPayload {
|
|
134
|
-
const part = token.split(".")[1] ?? "";
|
|
135
|
-
return JSON.parse(base64urlDecodeString(part)) as JwtPayload;
|
|
136
|
-
}
|
|
137
134
|
|
|
138
135
|
function encodeSessionCookie(session: OidcSession) {
|
|
139
136
|
return base64urlEncode(new TextEncoder().encode(JSON.stringify(session)));
|
|
@@ -285,7 +282,7 @@ function sessionFromPayload(payload: JwtPayload): OidcSession {
|
|
|
285
282
|
|
|
286
283
|
function applyTokenCookies(response: NextResponse, request: NextRequest, tokens: TokenResponse) {
|
|
287
284
|
const options = getCookieOptions(request);
|
|
288
|
-
const payload = parseJwtPayload(tokens.id_token!);
|
|
285
|
+
const payload = (parseJwtPayload(tokens.id_token!) ?? {}) as JwtPayload;
|
|
289
286
|
const expiresAt =
|
|
290
287
|
payload.exp ??
|
|
291
288
|
(tokens.expires_in ? Math.floor(Date.now() / 1_000) + tokens.expires_in : undefined);
|
|
@@ -388,7 +385,7 @@ export async function handleAuthorizationCallback(request: NextRequest) {
|
|
|
388
385
|
redirectUri: getRedirectUri(request),
|
|
389
386
|
tokenEndpoint: discovery.token_endpoint,
|
|
390
387
|
});
|
|
391
|
-
const payload = parseJwtPayload(tokens.id_token!);
|
|
388
|
+
const payload = (parseJwtPayload(tokens.id_token!) ?? {}) as JwtPayload;
|
|
392
389
|
if (savedNonce && payload.nonce && payload.nonce !== savedNonce) {
|
|
393
390
|
throw new Error("OIDC nonce mismatch.");
|
|
394
391
|
}
|
|
@@ -410,7 +407,7 @@ export async function getSessionFromCookies(): Promise<OidcSession> {
|
|
|
410
407
|
const idToken = cookieStore.get(oidcCookies.idToken)?.value;
|
|
411
408
|
if (idToken) {
|
|
412
409
|
try {
|
|
413
|
-
return sessionFromPayload(parseJwtPayload(idToken));
|
|
410
|
+
return sessionFromPayload((parseJwtPayload(idToken) ?? {}) as JwtPayload);
|
|
414
411
|
} catch {
|
|
415
412
|
// fall through to compact session cookie
|
|
416
413
|
}
|
|
@@ -467,7 +464,7 @@ export async function buildSessionResponse(_request?: NextRequest) {
|
|
|
467
464
|
status: 401,
|
|
468
465
|
});
|
|
469
466
|
}
|
|
470
|
-
return NextResponse.json(sessionFromPayload({ ...parseJwtPayload(idToken), exp: expiresAt }));
|
|
467
|
+
return NextResponse.json(sessionFromPayload({ ...(parseJwtPayload(idToken) ?? {}), exp: expiresAt } as JwtPayload));
|
|
471
468
|
}
|
|
472
469
|
|
|
473
470
|
export async function buildTokenResponse(request: NextRequest) {
|
package/src/_internal.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared internal utilities — not exported from package public API.
|
|
3
|
-
*/
|
|
4
|
-
import { base64urlDecodeString } from '@baseworks/core'
|
|
5
|
-
|
|
6
|
-
export function parseJwtPayload(token: string): Record<string, unknown> | null {
|
|
7
|
-
try {
|
|
8
|
-
const part = token.split('.')[1]
|
|
9
|
-
if (!part) return null
|
|
10
|
-
return JSON.parse(base64urlDecodeString(part)) as Record<string, unknown>
|
|
11
|
-
} catch {
|
|
12
|
-
return null
|
|
13
|
-
}
|
|
14
|
-
}
|