supabase-js
supabase-js copied to clipboard
The User object is null in Edge Function runtime with a valid authorization token
Bug report
The user object is null in Edge Function runtime with a valid authorization token.
Describe the bug
I'm trying to get the User object with a valid Authorization token to perform an insert on a specific table that contains the user id; the user object is always at runtime, even with a valid authorization token.
To Reproduce
- Create an Edge function and deploy it
// Get the authorization header from the request.
const authHeader = req.headers.get('Authorization').replace("Bearer ","")
// Client now respects auth policies for this user
supabaseClient.auth.setAuth(authHeader)
// set the user profile
const user = supabase.auth.user()
console.log(user);
>> null
Expected behavior
Returns the current Auth user with UUID.
Getting the same result from copy pasting sample code from the RESTful service.
Function call runs, but the user object is null and I can't access the database with my supabase client (assuming RLS blocks queries because the user is not authenticated).
myfunction/index.ts
import { serve } from "https://deno.land/[email protected]/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/[email protected]";
serve(async (req) => {
const { url, method } = req;
try {
const supabaseClient = createClient(
// Supabase API URL - env var exported by default.
Deno.env.get("SUPABASE_URL") ?? "",
// Supabase API ANON KEY - env var exported by default.
Deno.env.get("SUPABASE_ANON_KEY") ?? "",
// Create client with Auth context of the user that called the function.
// This way your row-level-security (RLS) policies are applied.
{
global: {
headers: { Authorization: req.headers.get("Authorization")! },
},
}
);
const {
data: { user },
} = await supabaseClient.auth.getUser();
// Null here
console.log("USER : ", user);
return new Response(JSON.stringify({ user: user }), {
headers: { "Content-Type": "application/json" },
status: 200,
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
headers: { "Content-Type": "application/json" },
status: 400,
});
}
});
Sample node app:
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'LOCAL HOST',
'SUPABASE_PUBLIC_KEY'
)
const { data: userData, error: userError } = await supabase.auth.signInWithPassword({
email: '[email protected]',
password: 'mypassword',
})
// Exists here
console.log("User Data: ", userData)
const { data, error } = await supabase.functions.invoke('myfunction')
Or maybe this is the issue... =/
No storage option exists to persist the session, which may result in unexpected behavior when using auth. If you want to set persistSession to true, please provide a storage option or you may set persistSession to false to disable this warning.
Hi everyone, we have a guide here on how to set up the auth context in your edge function correctly: https://supabase.com/docs/guides/functions/auth#auth-context
@Qw4z1 are you still facing this issue? You need to set persistSession to false when you create the client in your sample node app
As for your code in your edge function, did you check if req.headers.get("Authorization") returns a user's JWT? You should also be setting persistSession to false when you create the client here.
Hi everyone, we have a guide here on how to set up the auth context in your edge function correctly: https://supabase.com/docs/guides/functions/auth#auth-context
@Qw4z1 are you still facing this issue? You need to set
persistSessionto false when you create the client in your sample node appAs for your code in your edge function, did you check if
req.headers.get("Authorization")returns a user's JWT? You should also be settingpersistSessionto false when you create the client here.
Followed the guide, verified auth header returns JWT, set persistSession to false. Still getting null when calling getUser() and the missing sub claim error
// Create a Supabase client with the Auth context of the logged in user.
const supabaseClient = createClient<Database>(
// Supabase API URL - env var exported by default.
Deno.env.get("SUPABASE_URL") ?? "",
// Supabase API ANON KEY - env var exported by default.
Deno.env.get("SUPABASE_ANON_KEY") ?? "",
// Create client with Auth context of the user that called the function.
// This way your row-level-security (RLS) policies are applied.
{
global: {
headers: { Authorization: req.headers.get("Authorization")! },
},
auth: {
persistSession: false,
},
},
);
const { data: { user }, error } = await supabaseClient.auth.getUser();
console.log(user, error); // returns null
The error
[Info] null AuthApiError: invalid claim: missing sub claim
at le (https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:5282)
at eventLoopTick (ext:core/01_core.js:64:7)
at async Ie (https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:6069)
at async h (https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:5806)
at async https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:26219
at async m._useSession (https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:25008)
at async m._getUser (https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:26136)
at async https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:25999
at async https://esm.sh/v135/@supabase/[email protected]/esnext/gotrue-js.mjs:2:24294 {
__isAuthError: true,
name: "AuthApiError",
status: 401
}
I am having the same error, but was able to get the user as follows
const supabaseClient = createClient(
Deno.env.get("SUPABASE_URL") ?? "",
Deno.env.get("SUPABASE_ANON_KEY") ?? "",
{
global: {
headers: { Authorization: req.headers.get("Authorization") ?? "" },
},
},
);
const jwt = req.headers.get("Authorization")!.split(" ")[1];
const { data: { user }, error } = await supabaseClient.auth.getUser(jwt);
However, this is a different behavior from the documentation and this issue should be corrected
@Chipsnet thanks for figuring it out! In fact, the current behavior is correct and you have to pass the JWT token to getUser.
It's documentation says "Gets the current user details if there is an existing session.". Apparently, there's no session in the edge environment so it's required. Edge docs have to be fixed though.
This is super annoying and is a recent breaking change which has had serious consequences on our production services. Please FIX DOCS ASAP!
Setting authorization headers on new clients does not work as documented. The only solution to using clients within edge function is the undocumented solution identified by @Chipsnet
Hey guys, any update on this issue?
I tested everything above + https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/select-from-table-with-auth-rls/index.ts, but still getting null user.
What I'm trying to do is to trigger webhook with Edge Function, to update table based on any operation in another table.
any update on this issue?