|
1 | 1 | import { STATUS_CODE, STATUS_TEXT } from "https://deno.land/std/http/status.ts"; |
2 | 2 | import * as posix from "https://deno.land/std/path/posix/mod.ts"; |
3 | 3 |
|
4 | | -import * as jose from "https://deno.land/x/jose@v4.13.1/index.ts"; |
| 4 | +import * as jose from "jsr:@panva/jose@6"; |
5 | 5 |
|
6 | 6 | const SB_SPECIFIC_ERROR_CODE = { |
7 | 7 | BootError: |
@@ -29,8 +29,9 @@ const SB_SPECIFIC_ERROR_REASON = { |
29 | 29 | // OS stuff - we don't want to expose these to the functions. |
30 | 30 | const EXCLUDED_ENVS = ["HOME", "HOSTNAME", "PATH", "PWD"]; |
31 | 31 |
|
32 | | -const JWT_SECRET = Deno.env.get("SUPABASE_INTERNAL_JWT_SECRET")!; |
33 | 32 | const HOST_PORT = Deno.env.get("SUPABASE_INTERNAL_HOST_PORT")!; |
| 33 | +const JWT_SECRET = Deno.env.get("SUPABASE_INTERNAL_JWT_SECRET")!; |
| 34 | +const JWKS_ENDPOINT = Deno.env.get("SUPABASE_URL")! + "/auth/v1/.well-known/jwks.json"; |
34 | 35 | const DEBUG = Deno.env.get("SUPABASE_INTERNAL_DEBUG") === "true"; |
35 | 36 | const FUNCTIONS_CONFIG_STRING = Deno.env.get( |
36 | 37 | "SUPABASE_INTERNAL_FUNCTIONS_CONFIG", |
@@ -105,13 +106,28 @@ function getAuthToken(req: Request) { |
105 | 106 | return token; |
106 | 107 | } |
107 | 108 |
|
108 | | -async function verifyJWT(jwt: string): Promise<boolean> { |
| 109 | +async function verifyLegacyJWT(jwt: string): Promise<boolean> { |
109 | 110 | const encoder = new TextEncoder(); |
110 | 111 | const secretKey = encoder.encode(JWT_SECRET); |
111 | 112 | try { |
112 | 113 | await jose.jwtVerify(jwt, secretKey); |
113 | 114 | } catch (e) { |
114 | | - console.error(e); |
| 115 | + console.error('Symmetric Legacy JWT verification error', e); |
| 116 | + return false; |
| 117 | + } |
| 118 | + return true; |
| 119 | +} |
| 120 | + |
| 121 | +// Lazy-loading JWKs |
| 122 | +let jwks = null; |
| 123 | +async function verifyJWT(jwt: string): Promise<boolean> { |
| 124 | + try { |
| 125 | + if (!jwks) { |
| 126 | + jwks = jose.createRemoteJWKSet(new URL(JWKS_ENDPOINT)); |
| 127 | + } |
| 128 | + await jose.jwtVerify(jwt, jwks); |
| 129 | + } catch (e) { |
| 130 | + console.error('Asymmetric JWT verification error', e); |
115 | 131 | return false; |
116 | 132 | } |
117 | 133 | return true; |
@@ -162,7 +178,12 @@ Deno.serve({ |
162 | 178 | const isValidJWT = await verifyJWT(token); |
163 | 179 |
|
164 | 180 | if (!isValidJWT) { |
165 | | - return getResponse({ msg: "Invalid JWT" }, STATUS_CODE.Unauthorized); |
| 181 | + console.log('Asymmetric JWT verification failed; attempting legacy verification.') |
| 182 | + const isValidLegacyJWT = await verifyLegacyJWT(token); |
| 183 | + |
| 184 | + if (!isValidLegacyJWT) { |
| 185 | + return getResponse({ msg: "Invalid JWT" }, STATUS_CODE.Unauthorized); |
| 186 | + } |
166 | 187 | } |
167 | 188 | } catch (e) { |
168 | 189 | console.error(e); |
|
0 commit comments