supertokens-core
supertokens-core copied to clipboard
Add anonymous sessions
Properties we need:
- No database storage consumptions - since high traffic websites would needlessly occupy space.
- Created as soon as the first API call is made
- Anonymous session data is transferred to an authenticated session easily
- Enable / disable anonymous sessions - enabled by default.
- On unauthorised / logout, create a new anonymous session automatically.
- Have one persistent string that's the same across anonymous / authorised sessions, no matter how many times the switch occurs.
- A middleware will add the anonymous session JWT. This middleware will be called for all APIs, and will check if an authenticated session exists. If it does, it will do nothing, otherwise, it will add a new anonymous session if it doesn't already exist.
- The JWT payload contains an
anonymousId
, which is carry forwarded even to an authenticated session, and never changes (unless the user deletes the session). This is stored in a special field in access token - just like theuserId
. It is also accessible just like theuserId
. - The JWT signing key for the anonymous session will be static. The user can change it manually if they want to.
- An anonymous session must always exist - if the current anonymous session fails validation, a new one is created instead.
- An anonymous session is added as a cookie along with it's
front-token
andanti-csrf
token if required. - The session object in the SDKs will have a new
isAnonymous
function. We can determine if a token is anonymous or not based on if it has auserId
claim in it. - The session verification middleware exists in the same way as it does now. For routes that have no session verification middleware explicitly added, an implicit anonymous session verification middleware should be added.
- The anonymous session verification middleware should:
- Check if an authenticated session exists. If yes, do nothing and pass to next middleware
- If an anonymous session exists, try to verify it. If verification success, change the request object and pass on the session object.
- If the verification fails, or if there is no session at all, then create a new anonymous session.
- The
createNewSession
will delete the anonymous session, if it exists, and create a new authenticated session as usual. - The cookie key for an anonymous session will be different than the one for an authenticated session (or maybe not?). If a malicious party switches them, it won't lead to a security issue since the verification of sessions will fail.
- In the case of creating a new anonymous session, it must be treated like an authenticated session exists (on the frontend), even if it actually does not.
- There may be a need to have an authenticated session verification middleware that allows the API to be called even if an authenticated session doesn't exist (in this case, an anonymous session will automatically exist since that will be called before).
- If anonymous sessions are turned off, we still need to check if an anonymous session exists, and if it does, we need to remove it. This is so that is an app has it on, and then switches it off, current anonymous sessions will be removed, eventually.
- The payload from the anonymous session to the authenticated session will have to be transported by the user, manually.
- The payload from the authenticated session to the anonymous session will have to be transported by the user, manually.
- In case an anonymous session is being created automatically (no session exists, or unauthorised being called), then the existing payload is lost (but not the
anonymousId
). - In case of unauthorised, the creation of an anonymous session happens before the error callback is called. That is because the authenticated session is already revoked (from the frontend) before the callback is called.
- In case of try refresh token, nothing changes.
- In case of session theft detected, the creation of an anonymous session happens before the error callback is called. That is because the authenticated session is already revoked (from the frontend) before the callback is called.
- As a note,
Set-Cookie
is respected even for 4xx and 5xx status codes.
Discussion points:
- [ ] Does the cookie key for an anonymous session need to be different than that of an authenticated session? Initial thought is yes. Everything, from csrf to
front-token
to cookie key should be different so that it's east to clear out the right contents in the even that one type of session needs clearing. But perhaps that's not necessary? - [ ] Do we need to issue an
IdRefreshToken
for an anonymous session as well? - [ ] We need to draw a flow diagram for:
- anonymous sessions
- auth sessions
- anonymous -> auth sessions
- auth -> anonymous sessions
- So does that mean we'll have two middlewares? One for the session verification as we have now and another for the anonymous session? Or do we want both to be part of only one middleware?
- Let's say we want only one middleware which take cares of both the anonymous sessions as well as the authenticated sessions. Now the user has enabled anonymous session feature, what if for certain routes, user only wants to allow authenticated users. If a request made is currently having an anonymous session or no session associated, such request should throw error (401)
So does that mean we'll have two middlewares? One for the session verification as we have now and another for the anonymous session? Or do we want both to be part of only one middleware?
There will be two different, but the anonymous one will be automatically added by app.use()
(node example). Just like how the refresh middleware is added.
Let's say we want only one middleware
That's not true.. so, the point it irrelevant.
@rishabhpoddar Did this move anywhere? Interested in being able to obtain an anonymous session and the matching JWT.
It would simplify our GraphQL gateway security policy if all api requests must include a JWT but some queries would allow non-authenticated/anon roles.
Hey @andywirv you can already issue anonymous sessions using our JWT recipe. Initialise it and then create a new JWT like this
import JWT from "supertokens-node/recipe/jwt";
Supertokens.init({
appInfo: {
apiDomain: "..",
appName: "..",
websiteDomain: ".."
},
recipeList: [JWT.init()]
});
app.post("/create-anonymous-session", async (req, res) => {
let token = await JWT.createJWT({
sub: "<Generate random ID>",
isAnonymous: true,
// other info...
}, 3153600000) // 100 years validity.
if (token.status !== "OK") {
throw new Error('Should never come here');
}
res.json({
token: token.jwt
});
});
You can call this API from the frontend on page load if a regular session deosn't exist and if the anonymous JWT is not present. The response of this API can be saved in localstorage.
When making API requests, you can add this anonymous token if the frontend doesn't have aregular session.
The verification of the JWT from the graphql gateway can happen in the same way as the verification of the regular session's JWT.