hey! Quick question, is it possible somehow to all...
# support-questions-legacy
l
hey! Quick question, is it possible somehow to allow multi-user signins? Imagine Figma or Google, where you can switch users anytime you want. Technically it would be possible with JWTs and store them individually but I don't want to lose subdomain support. With cookies it's a bit different, since they have the same name and logging in another user would overwrite the previous one. I was thinking about a middy middleware that would basically combine cookies from multiple users. Combine them on the way out (after:) and select the proper one on the way in (before:, based on another header, like "x-current-user-id"). What do you think about this, or is there another way that I can achieve this? Thanks
r
Hey @legolas89110609 this is possible. Let me elaborate.
What you want to do is store an array of user ids in the access token payload and also store a field for current user in it.
This can be done via overriding the createNewSession function on the backend
You also want to override that function to detect if a session already exists (using the getSession function) and then not creating a new session in case it exists already
In case the session exists, you want to modify the access token payload to add the new userId in the session and also set the current user id to that one.
In all your APIs, instead of using session.getUserId, you want to instead use session.getAccessTokenPayload().currentUserId
For switching between users, you want to create an api that will modify the session payload’s currentUserId to the one you want to switch to.
There are other approaches to this as well. For example, you could create a new session each time you want to switch users, but also maintain that list of users you can switch to in that new session. This way, you can continue to use session.getUserId() in app your APIs. The downside to this is that each time you switch users, a new session is created. The older one will eventually expire. But this isn’t such a big problem anyway.
l
hey @rp_st , thanks for the quick response! I'm logged in with user X, I have the cookies for it, all fine. I now login with user Y. I have the current cookie on the login request that belongs to user X so I can basically create a new session for user Y and adding X in the access token payload like you mentioned above. All fine so far. But my cookies for user X will be overwritten by the ones from Y, isn't that right? That means that as soon as the session for X expires, it's gone, no refresh for that user. Only the last logged in user will have an autorefresh, right? Even if I have the user X userid in my Y session, I can't just change the currentUserId on switch since that would be a security issue as I see it, maybe user X was deleted in the meantime or something, I'll need to make the user login with X again
also, using the Session.getSession in createNewSession override seems tricky. It expects header rid: session (or disable csrf) but if I do that it breaks the login
r
> But my cookies for user X will be overwritten by the ones from Y, isn't that right? Yes. This is what you want. > Only the last logged in user will have an autorefresh, right? Yes. > Even if I have the user X userid in my Y session, I can't just change the currentUserId on switch since that would be a security issue as I see it, maybe user X was deleted in the meantime or something, I'll need to make the user login with X agai So when you want to switch users, you can do that by making an API that will: - Check if user X is in the session (you add this to the access token payload when user Y logged in) and check if X is not deleted. - Call the createNewSession with userId of
X
and putting Y in the access token payload so that you can switch to user Y later on if needed.
> using the Session.getSession in createNewSession override seems tricky. It expects header rid: session (or disable csrf) but if I do that it breaks the login You should be able to call with without any issues.. how are you calling it? And whats the error that you are getting?
l
const existingSession = await Session.getSession(input.res.event, input.res.event); (on lambda, using middy)
com.supertokens {t: "2022-12-04T14:34:08.137Z", message: "getSession: Returning TRY_REFRESH_TOKEN because custom header (rid) was not passed", file: "/opt/nodejs/node_modules/supertokens-node/lib/build/recipe/session/sessionFunctions.js:197:30" sdkVer: "12.1.1"}
com.supertokens {t: "2022-12-04T14:34:08.138Z", message: "errorHandler: Error is from SuperTokens recipe. Message: anti-csrf check failed. Please pass 'rid: "session"' header in the request, or set doAntiCsrfCheck to false for this API", file: "/opt/nodejs/node_modules/supertokens-node/lib/build/supertokens.js:318:30" sdkVer: "12.1.1"
r
can you try:
Copy code
await Session.getSession(input.req, input.res)
l
there is no input.res or input.req
wait, just res
r
oh sorry, it should be
input.options.req
and
input.options.res
l
req does not exist
r
also, you should call it with optional session flag cause during first login, there will be no session
l
2022-12-04T14:34:07.984Z e7ba1234-91ee-4845-b0a6-4fe904ebed5d INFO SESSION INPUT { res: AWSResponse { wrapperUsed: true, sendHTMLResponse: [Function (anonymous)], setHeader: [Function (anonymous)], setCookie: [Function (anonymous)], setStatusCode: [Function (anonymous)], sendJSONResponse: [Function (anonymous)], sendResponse: [Function (anonymous)], original: { version: '2.0', routeKey: '$default', rawPath: '/signin', rawQueryString: '', cookies: [Array], headers: [Object], requestContext: [Object], body: '{"formFields":[{"id":"email","value":"lEMAIL"},{"id":"password","value":"PASS"}]}', isBase64Encoded: false, supertokens: [Object] }, event: { version: '2.0', routeKey: '$default', rawPath: '/signin', rawQueryString: '', cookies: [Array], headers: [Object], requestContext: [Object], body: '{"formFields":[{"id":"email","value":"EMAIL"},{"id":"password","value":"PASS"}]}', isBase64Encoded: false, supertokens: [Object] }, statusCode: 200, content: '{}', responseSet: false, statusSet: false }, userId: 'UID', accessTokenPayload: { 'st-role': { v: [Array], t: 1670164447875 }, 'st-perm': { v: [Array], t: 1670164447983 } }, sessionData: {}, userContext: { _default: { request: [AWSRequest] } } }
r
ok right. So what you may want to do is to call
getSession
function in the login API instead with
input.options.req
and
input.options.res
and then add the returned session object to
input.userContext.session = session
and then read
input.userContext.session
in the
createNewSession
override
does this make sense?
oh wait.. actually a simpler way it to just do
Copy code
await getSession(input.userContext._default.request, input.res)
the request object is available in the userContext object
l
Session.getSession, right?
r
yes
and call it with optional session flag
Copy code
await getSession(input.userContext._default.request, input.res, {sessionRequired: false})
l
deploying
still getting 401 on login {"message":"try refresh token"}
r
and the logs?
l
same getSession: Returning TRY_REFRESH_TOKEN because custom header (rid) was not passed
and if I pass rid I break login
r
hmm.. thats weird. the request object should have that
rid
header in it
l
well it can't
r
Can you console log out
input.userContext._default.request
?
l
if I set it it breaks the login
with rid set {"error":"The middleware couldn't serve the API path /signin, method: post. If this is an unexpected behaviour, please create an issue here: https://github.com/supertokens/supertokens-node/issues"}
r
which recipe are you using?
and what rid are you setting?
l
message: "middleware: Not handling because recipe doesn't handle request path or method. Request path: /signin, request method: post
thirdpartyemailpass
r
set the
rid
as
thirdpartyemailpassword
and try
l
heh, this works!
r
ok nice
l
let me check the logs, if it found the session
it did, I have the session 😄
thanks!
r
nice
l
to clarify, without this change, out of the box, it worked without setting any rid header so I assumed for login it doesn't need to be set
r
yea cause normally, login doesn't call the
getSession
function
l
(I was making test requests from Paw, not from a ST lib)
r
and
getSession
protects against CSRF using this
rid
header.
l
got it, thanks!
3 Views