- Published on
Using Supabase Auth with Custom Middleware in Hono
- Authors
- Name
- Shelton Ma
supabaseMiddleware
Create Middleware 1. Features
The custom middleware provides the following functionality:
- Attach Supabase Client: Makes the Supabase client accessible via the context (
c
). - Attach Authenticated User to Context: Attaches a
supabaseAuth
object (UserResponse | null
) to the context. - Retrieve User from Cookies: Attempts to identify the user based on cookies.
- Retrieve User from Authorization Header: Uses the Bearer token in the Authorization header if available.
2. Example Middleware
// src/utils/hono/supabase-auth/index.ts
import { createClient } from "@/utils/supabase/server";
import { User } from "@supabase/auth-js";
import { SupabaseClient } from "@supabase/supabase-js";
import { Context, MiddlewareHandler } from "hono";
export const supabaseMiddleware: MiddlewareHandler = async (c, next) => {
// Attach Supabase client to the context
const supabase = await createClient();
const headers = c.req.raw.headers;
if (headers) {
headers.forEach((value, key) => {
c.res.headers.append(key, value);
});
const locationHeader = headers.get("location");
if (locationHeader) {
const validUrlPattern = /^https?:\/\/[^\s/$.?#].[^\s]*$/i;
if (validUrlPattern.test(locationHeader)) {
c.redirect(locationHeader, 307);
return;
} else {
return c.json({ error: "Invalid redirect URL" }, 400);
}
}
}
// try to get the user from the cookies
const { data: userFromCookie, error: errorFromCookie } =
await supabase.auth.getUser();
if (errorFromCookie) {
// Try to get the user from the Authorization header
const authHeader = c.req.header("Authorization");
if (!authHeader) {
return c.json({ error: "Authorization header missing" }, 401);
}
const token = authHeader.split(" ")[1];
if (!token) {
return c.json({ error: "Token missing in Authorization header" }, 401);
}
const { data: userFromToken, error } = await supabase.auth.getUser(token);
if (error) {
return c.json({ error: "Unauthorized" }, 401);
}
c.set("supabaseAuth", userFromToken);
} else {
c.set("supabaseAuth", userFromCookie);
}
c.set("supabase", supabase);
await next();
};
export const getAuth = (c: Context): User | null => {
return c.get("supabaseAuth") || null;
};
export const getSupabaseClient = (c: Context): SupabaseClient => {
return c.get("supabase");
};
Usage
1. Globally Enable supabaseMiddleware
// src/app/api/[[...route]]/route.ts
import { supabaseMiddleware } from "@/utils/hono/supabase-auth";
const app = new Hono().basePath("/api");
app.use("*", supabaseMiddleware);
2. Enable supabaseMiddleware for Specific Routes
import { supabaseMiddleware } from "@/utils/hono/supabase-auth";
const app = new Hono()
.get("/", supabaseMiddleware, (c) => {
...
return c.json({ data });
})
Access Authenticated User
import { getAuth } from "@/utils/hono/supabase-auth";
const user_id = getAuth(c)?.id;
if (!user_id) {
return c.json({ error: "Unauthorized" }, 401);
}