@stackframe/stack-shared 2.5.30 → 2.5.31

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @stackframe/stack-shared
2
2
 
3
+ ## 2.5.31
4
+
5
+ ### Patch Changes
6
+
7
+ - JWKS
8
+ - @stackframe/stack-sc@2.5.31
9
+
3
10
  ## 2.5.30
4
11
 
5
12
  ### Patch Changes
@@ -1,3 +1,21 @@
1
1
  import * as jose from "jose";
2
- export declare function encryptJWT(payload: any, expirationTime?: string): Promise<string>;
3
- export declare function decryptJWT(jwt: string): Promise<jose.JWTPayload>;
2
+ export declare function signJWT(issuer: string, payload: any, expirationTime?: string): Promise<string>;
3
+ export declare function verifyJWT(issuer: string, jwt: string): Promise<jose.JWTPayload>;
4
+ export declare function getPrivateJwk(): Promise<{
5
+ kty: string;
6
+ crv: string;
7
+ d: string;
8
+ x: string;
9
+ y: string;
10
+ }>;
11
+ export declare function getPublicJwkSet(): Promise<{
12
+ keys: Pick<{
13
+ kty: string;
14
+ crv: string;
15
+ d: string;
16
+ x: string;
17
+ y: string;
18
+ }, "kty" | "crv" | "x" | "y">[];
19
+ }>;
20
+ export declare function encryptJWE(payload: any, expirationTime?: string): Promise<string>;
21
+ export declare function decryptJWE(jwt: string): Promise<jose.JWTPayload>;
package/dist/utils/jwt.js CHANGED
@@ -1,14 +1,56 @@
1
1
  import * as jose from "jose";
2
2
  import { getEnvVariable } from "./env";
3
+ import elliptic from "elliptic";
4
+ import { globalVar } from "./globals";
5
+ import { encodeBase64 } from "./bytes";
6
+ import { pick } from "./objects";
3
7
  const STACK_SERVER_SECRET = jose.base64url.decode(getEnvVariable("STACK_SERVER_SECRET"));
4
- export async function encryptJWT(payload, expirationTime = "5m") {
8
+ export async function signJWT(issuer, payload, expirationTime = "5m") {
9
+ const privateJwk = await jose.importJWK(await getPrivateJwk());
10
+ return await new jose.SignJWT(payload)
11
+ .setProtectedHeader({ alg: "ES256" })
12
+ .setIssuer(issuer)
13
+ .setIssuedAt()
14
+ .setExpirationTime(expirationTime)
15
+ .sign(privateJwk);
16
+ }
17
+ export async function verifyJWT(issuer, jwt) {
18
+ const jwkSet = jose.createLocalJWKSet(await getPublicJwkSet());
19
+ const verified = await jose.jwtVerify(jwt, jwkSet, {
20
+ issuer,
21
+ });
22
+ return verified.payload;
23
+ }
24
+ export async function getPrivateJwk() {
25
+ const secretHash = await globalVar.crypto.subtle.digest("SHA-256", STACK_SERVER_SECRET);
26
+ const priv = new Uint8Array(secretHash);
27
+ const ec = new elliptic.ec('p256');
28
+ const key = ec.keyFromPrivate(priv);
29
+ const publicKey = key.getPublic();
30
+ return {
31
+ kty: 'EC',
32
+ crv: 'P-256',
33
+ d: encodeBase64(priv),
34
+ x: encodeBase64(publicKey.getX().toBuffer()),
35
+ y: encodeBase64(publicKey.getY().toBuffer()),
36
+ };
37
+ }
38
+ export async function getPublicJwkSet() {
39
+ const privateJwk = await getPrivateJwk();
40
+ const jwk = pick(privateJwk, ["kty", "crv", "x", "y"]);
41
+ return {
42
+ keys: [jwk]
43
+ };
44
+ }
45
+ export async function encryptJWE(payload, expirationTime = "5m") {
5
46
  return await new jose.EncryptJWT(payload)
6
47
  .setProtectedHeader({ alg: "dir", enc: "A128CBC-HS256" })
48
+ .setIssuer("stack")
7
49
  .setIssuedAt()
8
50
  .setExpirationTime(expirationTime)
9
51
  .encrypt(STACK_SERVER_SECRET);
10
52
  }
11
- export async function decryptJWT(jwt) {
53
+ export async function decryptJWE(jwt) {
12
54
  if (!jwt) {
13
55
  throw new Error("Provided JWT is empty");
14
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackframe/stack-shared",
3
- "version": "2.5.30",
3
+ "version": "2.5.31",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -33,18 +33,20 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "bcrypt": "^5.1.1",
36
+ "elliptic": "^6.5.7",
36
37
  "jose": "^5.2.2",
37
38
  "oauth4webapi": "^2.10.3",
38
39
  "uuid": "^9.0.1",
39
- "@stackframe/stack-sc": "2.5.30"
40
+ "@stackframe/stack-sc": "2.5.31"
40
41
  },
41
42
  "devDependencies": {
42
- "rimraf": "^5.0.5",
43
43
  "@types/bcrypt": "^5.0.2",
44
+ "@types/elliptic": "^6.4.18",
44
45
  "@types/react": "^18.2.66",
45
46
  "@types/uuid": "^9.0.8",
46
47
  "next": "^14.1.0",
47
- "react": "^18.2.0"
48
+ "react": "^18.2.0",
49
+ "rimraf": "^5.0.5"
48
50
  },
49
51
  "scripts": {
50
52
  "build": "tsc",