Is there a way to set the Supabase auth token manually?

Hi there!

Is there a way to set the Supabase auth token manually? I receive an auth token by calling the Supabase API via a REST Call and want to authenticate that way.

I am able to set the token via wwLib.wwPlugins.supabaseAuth.publicInstance.auth.setAuth(my_token).

I can also see, that the cookie is set correctly. The problem is that the auth module still shows isAuthenticated: false. I’m just guessing that WeWeb has an additional mechanism of checking the authenticated status.

I feel like @Alexis is the expert on this topic. Any advice on how to force the auth plugin to accept the token?

Or is there an easier way?

Thanks,
Max

Hi, you can try to call wwLib.wwPlugins.supabaseAuth.refreshAuthUser()

It should set weweb cookies (used for our private page system) and update the plugin variables (user and isAuthenticated) :slight_smile:

I will note to add an action to set it up manually

Thanks for the super-quick reply, Alexis!

Unfortunately, that did not work. I can set the token and call the function you provided. It does not give me any error, even says it set values for user and isAuthenticated. But it does not change anything:

Here is the log:
image

Here is my custom JS:

Any ideas?

BTW: I only returned the variables to see the results in the logs.

I figured out calling this function from javascript is the same as calling the action fetch user so I would prefer you to use the no-code action instead

Also, its an async function so from the javascript you may have to await to have the true result, but again, you can use the Fetch user action instead :slight_smile:

Also, for debugging purpose you can try to call await supabase.auth.getSession() after the setAuth, and log the result, the session should contain an user, share the result with me please

Hi Alexis!

Unfortunately, this throws an error. Seems like getSession() is not defined on wwLib.wwPlugins.supabaseAuth.publicInstance.auth

I used the command from the V1 instead:

const session = supabase.auth.session()

This gives me the same result as the setAuth:
image

The fetch user also does not work - as expected, I think, as it is the same call as in JS.

Is there anything else I can try?

Thanks for bearing with me :wink:

Yeah sorry I am working on the v2 upgrade and misled you with the wrong api, it was .session() as you understood :sweat_smile:

From the documentation, your setAuth should have returned an user but in your capture its still null so I don’t know, are your sure the jwt token is still valid and contain user information ? You can try to open it from an online tool so check if it contain user information, if true its weird it doesn’t show up in the result of setAuth, can be an issue with the v1 :thinking:

The JWT is valid:

The user null seems to be a Supabase thing :wink:
supabase.auth.setAuth(access_token) returning null user · supabase · Discussion #6913 (github.com)

When I call

const { user } = await supabase.auth.api.getUser(
  context.workflow["ea869a69-0dbc-4c12-aaba-39cbf8b70832"].result?.[
    "access_token"
  ]
);

And pass the access_token I receive from my REST Call, it gives me the user object:

image

So it seems the authentication works fine. WeWeb just does not see it…

Ok, so the session does not contain the user, that’s the issue, the SDK should refresh the user instead of only clearing it. I don’t know how to set the missing user in the SDK.

What you could do is merging the session with your fetched user

const session = wwLib.wwPlugins.supabaseAuth.publicInstance.auth.session()

const { user } = await supabase.auth.api.getUser(
  context.workflow["ea869a69-0dbc-4c12-aaba-39cbf8b70832"].result?.[
    "access_token"
  ]
);

wwLib.wwPlugins.supabaseAuth.refreshAuthUser({...session, user})

Something like that will probably works but the issue is the sdk session still miss the user and it will be erased again in the next refresh call, in the next Fetch User call, because we retrieve the user from the memory of the sdk.

Maybe the call to supabase.auth.api.getUser refresh the memory ? Did you try to call it before calling refreshAuthUser ?

Thank you very much for your help, Alexis!

This seems to be a Supabase V1 issue: verifyOTP response causes session to not be persisted, auto-refresh not to be triggered, & user to not be set correctly · Issue #113 · supabase/gotrue-js (github.com)

You are right, Supabase does not set the user object. I could make it work by doing it like this:

const supabase = wwLib.wwPlugins.supabaseAuth.publicInstance;

// Get data from previous step
const verifyOtpResult =
  context.workflow["ea869a69-0dbc-4c12-aaba-39cbf8b70832"].result;

// Save the session manually
supabase.auth._saveSession({ ...verifyOtpResult});

// Notify subscribers
supabase.auth._notifyAllSubscribers("SIGNED_IN");

// Solution found here: https://github.com/supabase/gotrue-js/issues/113

// Fake update user data. This will refresh the user in the Supabase SDK
await supabase.auth.update({});

I know this is not optimal, as I call internal Supabase functions. But it will do until you release the Supabase V2 plugin. I think you are already working on that :wink:

Anyways, thanks a ton! I really appreciate it!

1 Like

UPDATE March 2024: Note that WeWeb added the refresh session workflow step


Thanks for the info in this thread; I used it to solve my own use-case. Posting what I did here in case it helps someone. Supabase now has a beta feature Supabase Auth Hooks Beta custom access tokens to add/remove claims based on auth hooks, e.g. logging in.

Also if you update a custom claim on the server side you may want to manually refresh, in multi-tenant cases where you want to “log out of an organization” and into another by adding a custom claim to the JWT.

So to do it with javascript you can do this to manually get a new access token with the updated claims in it (assuming you already set the custom claims with the auth hook or somehow server side or with a WeWeb update user workflow action-- however on the update user action remember they can do that themselves so you can’t 100% trust that on the back end).

const supabase = wwLib.wwPlugins.supabase.instance;
const { data, error } = await supabase.auth.refreshSession();
// Optionally, handle any error
if (error) {
  console.error("Error refreshing session:", error);
  // Handle the error appropriately
}
// To return the data for further processing, add return data;

However, it appears WeWeb is not notified about this so then you need a “fetch user” supabase workflow step right after to tell WeWeb’s plugin to get the new access token. So then you’re all set- you have the new JWT in WeWeb with the updated claims for real. The claim is just in the JWT, not the actual user app metadata, so WeWeb does not seem to extract it from the JWT and make the claims available in the front end but if you copy the actual access token and decode the JWT you’ll see the claims in there-- so it’s best used for validation on the back end unless WeWeb updates it to make it where the actual decoded JWT overrides the fetch user data.

Note that according to Supabase this invalidates the old access token because refreshSession() method returns a new access token and refresh token pair, which replaces the old pair. The old access token is no longer valid and should not be used for any further requests (that’s another reason why we need to fetch user again to get the new token too). Since refresh tokens can only be used once, after calling refreshSession(), the old refresh token is also invalidated and cannot be used again.

Side note if you use the of the update user Supabase workflow action which updates the user metatadta in the auth.users table, the existing access token in the front end does not get refreshed (at the time of writing, WeWeb puts the new update in the browser and is referenceable as a variable, but it does not actually get a new token with the claim in the JWT-- I have a ticket in with WeWeb about that).

Also at the time of this writing, wwLib.wwPlugins.supabase.instance.refreshSession() does not work to do the supabase.auth.refreshSession but if you do what I have above with const supabase then awat supabase auth.refreshSession() it works

1 Like