@planetlogin/core 0.3.0 → 0.4.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/dist/index.d.ts +3 -1
- package/dist/index.js +34 -5
- package/dist/keygen.js +9 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -26,7 +26,8 @@ declare function signSession(claims: SessionClaims, opts?: {
|
|
|
26
26
|
audience?: string;
|
|
27
27
|
ttlSeconds?: number;
|
|
28
28
|
}): Promise<string>;
|
|
29
|
-
/** Verify a session token against our own key material (what a downstream does).
|
|
29
|
+
/** Verify a session token against our own key material (what a downstream does).
|
|
30
|
+
* Transparently decrypts a JWE-wrapped token first when encryption is on. */
|
|
30
31
|
declare function verifySession(token: string): Promise<jose.JWTPayload>;
|
|
31
32
|
declare function signMagicToken(identifier: string, ttlSeconds?: number): Promise<string>;
|
|
32
33
|
/** Returns {identifier, jti} if the token is a valid, unexpired magic token, else null. */
|
|
@@ -152,6 +153,7 @@ interface PlanetLoginConfig {
|
|
|
152
153
|
audience?: string;
|
|
153
154
|
ttlSeconds?: number;
|
|
154
155
|
algorithm?: 'EdDSA' | 'RS256' | 'ES256' | 'HS256';
|
|
156
|
+
encrypt?: boolean;
|
|
155
157
|
};
|
|
156
158
|
session?: {
|
|
157
159
|
store?: 'none' | 'memory' | 'redis' | 'sqlite' | 'downstream';
|
package/dist/index.js
CHANGED
|
@@ -103,7 +103,10 @@ import {
|
|
|
103
103
|
generateKeyPair,
|
|
104
104
|
generateSecret,
|
|
105
105
|
importPKCS8,
|
|
106
|
-
createLocalJWKSet
|
|
106
|
+
createLocalJWKSet,
|
|
107
|
+
CompactEncrypt,
|
|
108
|
+
compactDecrypt,
|
|
109
|
+
base64url
|
|
107
110
|
} from "jose";
|
|
108
111
|
import { readFileSync as readFileSync2 } from "fs";
|
|
109
112
|
var ASYMMETRIC = ["EdDSA", "RS256", "ES256"];
|
|
@@ -161,12 +164,38 @@ async function verifier() {
|
|
|
161
164
|
if (k.alg === "HS256") return k.verify;
|
|
162
165
|
return createLocalJWKSet({ keys: [k.pubJwk] });
|
|
163
166
|
}
|
|
167
|
+
var jweKey = null;
|
|
168
|
+
function encryptEnabled() {
|
|
169
|
+
return process.env.PLANETLOGIN_JWT_ENCRYPT === "true";
|
|
170
|
+
}
|
|
171
|
+
function getJweKey() {
|
|
172
|
+
if (jweKey) return jweKey;
|
|
173
|
+
const env = process.env.PLANETLOGIN_JWE_KEY;
|
|
174
|
+
if (env) {
|
|
175
|
+
jweKey = base64url.decode(env);
|
|
176
|
+
if (jweKey.length !== 32) throw new Error("PLANETLOGIN_JWE_KEY must decode to 32 bytes (base64url)");
|
|
177
|
+
} else {
|
|
178
|
+
console.warn("[planetlogin] WARNING: PLANETLOGIN_JWT_ENCRYPT is on but no PLANETLOGIN_JWE_KEY \u2014 using an EPHEMERAL key. Tokens cannot be decrypted across instances/restarts. Do not use in production.");
|
|
179
|
+
jweKey = crypto.getRandomValues(new Uint8Array(32));
|
|
180
|
+
}
|
|
181
|
+
return jweKey;
|
|
182
|
+
}
|
|
183
|
+
async function maybeEncrypt(jws) {
|
|
184
|
+
if (!encryptEnabled()) return jws;
|
|
185
|
+
return new CompactEncrypt(new TextEncoder().encode(jws)).setProtectedHeader({ alg: "dir", enc: "A256GCM", cty: "JWT" }).encrypt(getJweKey());
|
|
186
|
+
}
|
|
187
|
+
async function maybeDecrypt(token) {
|
|
188
|
+
if (token.split(".").length !== 5) return token;
|
|
189
|
+
const { plaintext } = await compactDecrypt(token, getJweKey());
|
|
190
|
+
return new TextDecoder().decode(plaintext);
|
|
191
|
+
}
|
|
164
192
|
async function signSession(claims, opts = {}) {
|
|
165
193
|
const k = await getKeys();
|
|
166
|
-
|
|
194
|
+
const jws = await new SignJWT({ email: claims.email, name: claims.name, locale: claims.locale }).setProtectedHeader({ alg: k.alg, kid: k.kid }).setSubject(claims.sub).setIssuedAt().setExpirationTime(`${opts.ttlSeconds ?? 3600}s`).setIssuer(opts.issuer ?? "planetlogin").setAudience(opts.audience ?? "planetlogin").sign(k.sign);
|
|
195
|
+
return maybeEncrypt(jws);
|
|
167
196
|
}
|
|
168
197
|
async function verifySession(token) {
|
|
169
|
-
const { payload } = await jwtVerify(token, await verifier(), {
|
|
198
|
+
const { payload } = await jwtVerify(await maybeDecrypt(token), await verifier(), {
|
|
170
199
|
issuer: "planetlogin",
|
|
171
200
|
audience: "planetlogin"
|
|
172
201
|
});
|
|
@@ -455,12 +484,12 @@ async function fetchProfile(p, accessToken) {
|
|
|
455
484
|
}
|
|
456
485
|
|
|
457
486
|
// src/oauthState.ts
|
|
458
|
-
import { EncryptJWT, jwtDecrypt, base64url } from "jose";
|
|
487
|
+
import { EncryptJWT, jwtDecrypt, base64url as base64url2 } from "jose";
|
|
459
488
|
var stateKey = null;
|
|
460
489
|
function getStateKey() {
|
|
461
490
|
if (stateKey) return stateKey;
|
|
462
491
|
const env = process.env.PLANETLOGIN_STATE_KEY;
|
|
463
|
-
stateKey = env ?
|
|
492
|
+
stateKey = env ? base64url2.decode(env) : crypto.getRandomValues(new Uint8Array(32));
|
|
464
493
|
if (stateKey.length !== 32) throw new Error("PLANETLOGIN_STATE_KEY must decode to 32 bytes");
|
|
465
494
|
return stateKey;
|
|
466
495
|
}
|
package/dist/keygen.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// bin/keygen.ts
|
|
4
|
-
import { generateKeyPair, exportPKCS8, exportJWK } from "jose";
|
|
4
|
+
import { generateKeyPair, exportPKCS8, exportJWK, base64url } from "jose";
|
|
5
5
|
import { writeFileSync } from "fs";
|
|
6
|
+
if (process.argv.includes("--jwe")) {
|
|
7
|
+
const key = base64url.encode(crypto.getRandomValues(new Uint8Array(32)));
|
|
8
|
+
process.stdout.write(key + "\n");
|
|
9
|
+
console.error("\n# \u2191 32-byte JWE key (base64url). Shared out of band with services that read claims. Then set:");
|
|
10
|
+
console.error("# PLANETLOGIN_JWT_ENCRYPT=true");
|
|
11
|
+
console.error(`# PLANETLOGIN_JWE_KEY=${key}`);
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
6
14
|
var { privateKey, publicKey } = await generateKeyPair("EdDSA", { extractable: true });
|
|
7
15
|
var pem = await exportPKCS8(privateKey);
|
|
8
16
|
var pubJwk = await exportJWK(publicKey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planetlogin/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "PlanetLogin auth core — framework-agnostic flows, JWT, crypto, downstream contract. Consumed by every flavor; the HTTP binding stays per-framework.",
|
|
6
6
|
"exports": {
|