I have a custom backend that needs to authenticate users before letting them request some Express endpoints.
It works that way: NextJS (front-end) sends a request to NodeJS/Express (backend) with a Bearer token (the access_token of the session).
For that, I use the access_token on the frontend thanks to supabase.auth.getSession().
But, when submitting, I get the following error:
AuthApiError: invalid claim: missing sub claim
When using the Supabase auth debugger, I have:
GoTrueClient@4 (0.0.0) #_recoverAndRefresh() session from storage null
GoTrueClient@4 (0.0.0) #_recoverAndRefresh() session is not valid
GoTrueClient@4 (0.0.0) #_recoverAndRefresh() end
GoTrueClient@4 (0.0.0) #_handleVisibilityChange()
GoTrueClient@4 (0.0.0) #_initialize() end
GoTrueClient@4 (0.0.0) #_acquireLock lock released for storage key sb-ypvazegvykknqzcjdtcs-auth-token
GoTrueClient@4 (0.0.0) #_acquireLock end
GoTrueClient@4 (0.0.0) #_acquireLock begin -1
GoTrueClient@4 (0.0.0) #_acquireLock lock acquired for storage key sb-ypvazegvykknqzcjdtcs-auth-token
GoTrueClient@4 (0.0.0) #_useSession begin
GoTrueClient@4 (0.0.0) #__loadSession() begin
GoTrueClient@4 (0.0.0) #_acquireLock begin -1
GoTrueClient@4 (0.0.0) #_acquireLock end
GoTrueClient@4 (0.0.0) #getSession() session from storage null
GoTrueClient@4 (0.0.0) #__loadSession() end
GoTrueClient@4 (0.0.0) #_useSession begin
GoTrueClient@4 (0.0.0) #__loadSession() begin
GoTrueClient@4 (0.0.0) INITIAL_SESSION callback id 0af5b134-694b-42fa-bc6d-f63c289b2488 session null
GoTrueClient@4 (0.0.0) #getSession() session from storage null
GoTrueClient@4 (0.0.0) #__loadSession() end
GoTrueClient@4 (0.0.0) #_useSession end
GoTrueClient@4 (0.0.0) #_useSession end
Here is the complete Middleware code:
const { createClient } = require("@supabase/supabase-js");
const jwtDecode = require("jwt-decode");
async function authenticate(req, res, next) {
try {
// Créer une instance de Supabase client
const supabase = createClient(
"REMOVED_FOR_PRIVACY",
"REMOVED_FOR_PRIVACY",
{
auth: {
autoRefreshToken: false,
detectSessionInUrl: false,
persistSession: false,
localStorage: false,
debug: true
}
}
);
// Récupérer le jeton d'authentification depuis les en-têtes de la requête
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: "Unauthorized. No token" });
} else {
const jwt = token.split("Bearer ").pop();
// On veut ensuite décrypter le token JWT
const datadecoded = jwtDecode.jwtDecode(jwt);
console.log(datadecoded);
// Vérifier si le jeton est valide en utilisant Supabase
const response = await supabase.auth.getUser();
console.log(response);
if (!response.data.user) {
// Si l'utilisateur n'est pas authentifié ou s'il y a une erreur, renvoyer une erreur 401
return res.status(401).json({ error: "Unauthorized. No user" });
}
req.user = user;
next();
}
} catch (error) {
console.error("Error during authentication:", error);
return res.status(500).json({ error: "Internal Server Error" });
}
}
module.exports = {
authenticate
};
I expected to get a User object. But got:
data: { user: null }, error: AuthApiError: invalid claim: missing sub claim
When using jwt.io, or a built-in NodeJS JWT decoder, I get:
{
"aud": "authenticated",
"exp": 1709127893,
"iat": 1709124293,
"iss": "REMOVED_FOR_PRIVACY",
"sub": "85441283-ae4e-489d-9a6a-492b6f7748d7",
"email": "REMOVED_FOR_PRIVACY",
"phone": "",
"app_metadata": {
"provider": "email",
"providers": [
"email"
]
},
"user_metadata": {},
"role": "authenticated",
"aal": "aal1",
"amr": [
{
"method": "password",
"timestamp": 1709111568
}
],
"session_id": "746acbc5-8d05-4a41-b5a8-fdc21a356ed9"
}
I can see that the error is maybe coming from GoTrue used by Supabase.
You can get the auth users like this: