I update the access token payload in `createNewSession`, what is the best way to refresh this inform...
j
I update the access token payload in
createNewSession
, what is the best way to refresh this information? I use
input.userId
to lookup the info to put into the access token. Also wondering if it's the right spot, I need to access the info on the client and the server
r
hey @Jake
createNewSession is the right place.
You could use a custom claim to refresh the info at a certain time interval since the last refresh. if you can tell me more about the use case, I can share some code
j
Create new session works, basically storing the roles in the access token. And need to refresh when they are edited
Copy code
override: {
    functions: (originalImplementation) => {
        return {
            ...originalImplementation,
            createNewSession: async (input) => {
                console.log('creating session', input)
                const queryExecutor = this.options.getQueryExecutor(
                    input.userId,
                )

                const claims = await getClaimsForUser(
                    queryExecutor,
                    input.userId,
                )
                const user = await getUserById(input.userId)
                const accessTokenPayload = {
                    email: user?.email,
                    organizations: claims.existingOrganizationClaims,
                }

                // This goes in the access token, and is availble to read on the frontend
                // This is stored in the db against the sessionHandle for this session
                return originalImplementation.createNewSession({
                    ...input,
                    accessTokenPayload,
                })
            },
        }
    },
},
r
So when you edit the roles, you can use session.mergeIntoAccessTokenPayload function to update the roles in the session. You can do that for the current session, as well as loop through all sessions of the user and update those.
For the other sessions, the update will be automatically reflected when the session refreshes.
A more elegant way of doing this is to build a session claim + validator and use that in your app. A session claim essentially auto refreshes the claims periodically depending on the validator that’s used. But this is only available in the newer versions of the SDK - which version are you using?
j
I can upgrade to the latest version
I'm pretty recent
r
@porcellus can help here with creating a custom session claim for your use case.
p
Hi
A quick run-down, since we haven't produced a full documentation for this yet:
The easiest way to get them is creating an instance of
PrimitiveClaim
or
PrimitiveArrayClaim
. I think you'd need
PrimitiveArrayClaim
(assuming
existingOrganizationClaims
is an array of strings). This way, you can add validators to
verifySession
to check the value before it gets to the API implementation (it'll return a 403 if the validator doesn't pass). These validators will refresh the value in the access token if necessary. The
PrimitiveArrayClaim
constructor takes a few options: `key`: an identifier specifying where we should store the value in the access token. `fetchValue`: an async function that returns the value you want to store (e.g.:
claims.existingOrganizationClaims
) `defaultMaxAgeInSeconds`: you can specify a claim-level default for the validators that check the last time the claim was fetched. You can add them during session creation like this:
Copy code
Session.init({
                        override: {
                            functions: (oI) => ({
                                ...oI,
                                createNewSession: async (input) => {
                                    input.accessTokenPayload = {
                                        ...input.accessTokenPayload,
                                        ...(await CustomClaim.build(input.userId, input.userContext)),
                                    };
                                    return oI.createNewSession(input);
                                },
                            }),
                        },
                    }),
Other than that, you could use it exactly like the
UserRoleClaim
from the UserRoles recipe. For example check here to see how to check the value in your APIs: https://supertokens.com/docs/emailpassword/user-roles/protecting-routes
I'm happy to elaborate on any part of it, just let me know where you need more detail πŸ™‚
also, any feedback on the interface/usability of this feature would be welcome πŸ™‚
j
Will digest this and have a crack, then will let you know. Thanks ❀️
The "These validators will refresh the value in the access token if necessary" comment is something i'm interested in
I have adding the claims to the session, and using them on the client/in routes to protect things
The bit I am unsure about is if I can programatically refresh them. My ideal is on the frontend to be able to just call refreshSession then that refreshes those claims in the access token, rather than having to put changes in my code to update it, but I can do that too. I will try that for now
That is, using mergeIntoAccessTokenPayload
p
You can refresh it using
session.fetchAndSet(CustomClaim)
that'll handle mergeIntoAccessTokenPayload
Calling session refresh fills a very different role, so doing that will not refresh the claims. In this case you have to add an endpoint to your API that'll handle this.
The automatic refreshing refers to validators: so if you call an endpoint that has a validator that requires a fresh value (validators have an optional
maxAgeInSeconds
parameters) that'll refresh it from the DB
I mean using the func you provided as fetchValue.
on the frontend you can achieve a similar thing if you create the claim there as well.
j
makes sense, what I might do is set a flag on the request then a middleware can call fetchAndSet with the latest claims
is fetchAndSet or mergeIntoAccessTokenPayload the best way to go for this approach?
p
I'd say
fetchAndSet
also, I'm not sure if you need to set a flag on the request or is the refresh time/max age controlled from the frontend?
j
I don't want to couple my APIs which modify the data which causes the claims to change directly to supertokens
p
ah I see. so this isn't a time based refresh.
j
But I do know the APIs which impact claims. So I can set a flag on the request somewhere which says claimsChanged, then before the response gets sent back I can update the claims
p
that makes sense πŸ™‚
j
Ah, i didn't say that, sorry. Yeah context is adding another organisation or leaving one
Would
updateAccessTokenPayload
be enough?
or am i just on an older sdk
p
If you have access to claims, that should be fairly recent and have a
fetchAndSetClaim
on the session object.
50 Views