chore: add custom-jwt-validation example (#40438)

This commit is contained in:
Kalleby Santos authored and GitHub committed 2025-11-14 10:45:38 +00:00
1 parent 9b784791bb
commit 27f8143b66
4 files changed
+155

No files matched your search

@@ -0,0 +1,60 @@
// Clerk as a third-party provider alongside Supabase Auth.
// Use this template to validate tokens issued by Clerk integration
import * as jose from "https://deno.land/x/jose@v4.14.4/index.ts";
// Obtain from https://clerk.com/setup/supabase
// Must supply this value from function env
const AUTH_THIRD_PARTY_CLERK_DOMAIN = Deno.env.get(
"AUTH_THIRD_PARTY_CLERK_DOMAIN",
);
export function getAuthToken(req: Request) {
const authHeader = req.headers.get("authorization");
if (!authHeader) {
throw new Error("Missing authorization header");
}
const [bearer, token] = authHeader.split(" ");
if (bearer !== "Bearer") {
throw new Error(`Auth header is not 'Bearer {token}'`);
}
return token;
}
async function verifyJWT(jwt: string): Promise<boolean> {
try {
const JWK = jose.createRemoteJWKSet(
new URL(AUTH_THIRD_PARTY_CLERK_DOMAIN ?? ""),
);
await jose.jwtVerify(jwt, JWK, {
algorithms: ["RS256"],
});
} catch (err) {
console.error(err);
return false;
}
return true;
}
// Validates authorization header
export async function AuthMiddleware(
req: Request,
next: (req: Request) => Promise<Response>,
) {
if (req.method === "OPTIONS") return await next(req);
try {
const token = getAuthToken(req);
const isValidJWT = await verifyJWT(token);
if (isValidJWT) return await next(req);
return Response.json({ msg: "Invalid JWT" }, {
status: 401,
});
} catch (e) {
console.error(e);
return Response.json({ msg: e?.toString() }, {
status: 401,
});
}
}
@@ -0,0 +1,55 @@
// Default supabase JWT verification
// Use this template to validate tokens issued by Supabase default auth
import * as jose from "https://deno.land/x/jose@v4.14.4/index.ts";
// Automatically supplied by Supabase
const JWT_SECRET = Deno.env.get("JWT_SECRET");
export function getAuthToken(req: Request) {
const authHeader = req.headers.get("authorization");
if (!authHeader) {
throw new Error("Missing authorization header");
}
const [bearer, token] = authHeader.split(" ");
if (bearer !== "Bearer") {
throw new Error(`Auth header is not 'Bearer {token}'`);
}
return token;
}
async function verifyJWT(jwt: string): Promise<boolean> {
const encoder = new TextEncoder();
const secretKey = encoder.encode(JWT_SECRET);
try {
await jose.jwtVerify(jwt, secretKey);
} catch (err) {
console.error(err);
return false;
}
return true;
}
// Validates authorization header
export async function AuthMiddleware(
req: Request,
next: (req: Request) => Promise<Response>,
) {
if (req.method === "OPTIONS") return await next(req);
try {
const token = getAuthToken(req);
const isValidJWT = await verifyJWT(token);
if (isValidJWT) return await next(req);
return Response.json({ msg: "Invalid JWT" }, {
status: 401,
});
} catch (e) {
console.error(e);
return Response.json({ msg: e?.toString() }, {
status: 401,
});
}
}
@@ -0,0 +1,21 @@
# custom-jwt-validation
This function exemplifies how to use a custom JWT validation.
Since Supabase legacy JWT Secret will be deprecated, users that would like to verify JWT or integrate with a custom provider should implement it manually.
> see [Upcoming changes to Supabase API Keys #29260](https://github.com/orgs/supabase/discussions/29260)
To simplify this task, Supabase provides a collection of JWT validation examples
that can be found at [`_shared/jwt/`](https://github.com/supabase/supabase/blob/main/examples/edge-functions/supabase/functions/_shared/jwt) folder.
## Setup
1. Copy/download the JWT template, then import and use it inside your edge function.
```bash
wget https://raw.githubusercontent.com/supabase/supabase/refs/heads/main/examples/edge-functions/supabase/functions/_shared/jwt/<template>.ts
```
2. Add any required Environment-Variable to a `.env` file, see inside of the
respective `_shared/jwt/template.ts` file to find which variables is required.
@@ -0,0 +1,19 @@
// Using 'default' Supabase auth middleware
// Change to a specific provider by importing like that:
// import { AuthMiddleware } from "../_shared/jwt/clerk.ts";
import { AuthMiddleware } from "../_shared/jwt/default.ts";
interface reqPayload {
name: string;
}
Deno.serve((r) =>
AuthMiddleware(r, async (req) => {
const { name }: reqPayload = await req.json();
const data = {
message: `Hello ${name} from foo!`,
};
return Response.json(data);
})
);