Netlify identity - app_metadata.roles value appears to be cached or not refreshable

From a Stripe subscription change hook, I set the role of a given user, and I KNOW the role is being set correctly because I see the correct role value in the Identity UI on my Netlify dashboard. (I have a ‘free’, ‘pro’, and ‘premium’ tier system and the roles match those names)

The problem is, the only way I can see the actual role change on the client side is if this user logs out and logs in again. Obviously, this is not optimal. If the user does not log out, I can reload the page again and again, and query:

context.clientContext.user.app_metadata.roles

in my serverless function, but it is always the pre-subscription change value. (i.e. if I upgrade to pro from free, I continue to see only free as my role value, even though in my Netlify identity UI for the user I see the ‘pro’ role value)

Is there something I need to do on the client-side or in the serverless function to ensure I am querying the NEWEST app_metadata.roles value?

Thank you to anyone who can give a few pointers!

Greetings, @fullStackChris! :wave:t2:

And welcome to The Community :netliheart:

It is correct that the browser-side JWT won’t automatically update even though the roles associated to that user server-side have changed. This is in part due to the nature of distributed auth systems, and it’s designed that way. I don’t necessarily have particular literature to link to at the moment regarding the architecture and nature of JWT and distributed auth, but it should be a brief search away :+1:t2:

To the point, when a user logs in and is granted a fresh JWT (And a refresh token which can be used to refresh that JWT), that JWT represents a fully authenticated user and needs no further input from Netlify Identity / GoTrue at that time. The JWT is a stand-alone, valid representation of proof that that user is who they say they are. When that JWT gets sent to a Function, the Function correctly sees the user for who they are based on the valid JWT, but as you’re noticing, the Roles that Function reads are the roles directly within the JWT, not a cross-reference to the roles that are currently stored in GoTrue.

So anyway, all the theory and logistics aside, it’s correct that your external change to a user’s role has no impact on the user’s JWT in-browser.

But there are ways to do what you’re looking to do. I wrote react-netlify-identity-gotrue and created a specific function just for this case, I called it .refreshUser():

This method is a utility to forcibly refresh the local user’s information and authorization. While not ostensibly the most useful functionality, it presents a particular use case for when you know a user’s data has been altered externally. This typically isn’t the case - a user’s own identity.user data tends to only be changed by that user but if the user kicks off a process that externally alters the user data, this method can be useful.

But be aware that this is not the same method in gotrue-js or other Netlify Identity libraries (not sure which client library you’re using).

If you can’t / don’t want to wire this up client side, or if your external changes aren’t kicked off from the client/browser at all, then you can use the GoTrue admin methods to actually reach out and get the latest user model from GoTrue whenever that user hits your function… effectively allowing you to both authenticate that the true user called your function and get the latest GoTrue data for that user in the Function before doing other things :slight_smile: let me know if that’s the direction you want to go and I can provide some pointers


Jon

1 Like

Hi Jon, you’ve literally answered as I was writing this: I’ve discovered the issue.I needed to refresh the token. In my case, I was using the netlify-identity-widget, so I needed to pass the ‘true’ parameter into the refresh function, to force the refresh on the token even though it isn’t expired:

netlifyIdentity.refresh(true)

One last question: is there a disadvantage to refreshing all the time? There must be I guess… this is fine though, I can monitor that subscription change event and only force a refresh!

Thank you for your response, I’ll check out that react-netlify-identity-gotrue!

1 Like

Great! It’s been a few months since I’ve been through the netlify-identity-widgetgotrue-js stack, but yes I believe calling refresh with true should truly force the refresh to happen. There’s actually this discussion on GitHub talking about the recommendation to refresh before every call to a Function:

But I think that pertains more to an expired token, not one that’s out of sync with GoTrue’s current state for that user. My library takes a lot of cues from both of those issues :stuck_out_tongue: (shameless plug :wink: )

Nope! It’s all asynchronous so it’s not blocking anything as far as UI interactions go. I guess you could make the case that it burns some CPU / power and that has implications for mobile devices… but as long as you’re not doing it every minute I’m sure that relatively nothing. A refresh token is pretty much just 1 HTTP call and a few lines of JS processing the response.


Jon

2 Likes

A post was split to a new topic: VueJS app out of sync after role updated externally via Netlify functions