Working with multiple API endpoints
To enable use of sessions for multiple API endpoints, you need to use the sessionTokenBackendDomain
config on the frontend and cookieDomain
on the backend Session.init
function call.
important
- All your API endpoints must have the same top level domain. For example, they can be
{"api.example.com", "api2.example.com"}
, but they cannot be{"api.example.com", "api.otherdomain.com"}
. - The backend config (step 1 and 2) need to only be done if you are using cookie based auth (which is the default for web apps). If using header based auth, please skip to step 3.
#
Step 1) Set Cookie Domain in the Backend Config (only applicable for cookie based auth)You need to set the cookieDomain
value to be the common top level domain. For example, if your API endpoints are {"api.example.com", "api2.example.com", "api3.example.com"}
, the common portion of these endpoints is ".example.com"
(The dot is important). So you would need to set the following:
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
supertokens: {
connectionURI: "...",
},
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
Session.init({
cookieDomain: ".example.com",
})
]
});
import (
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
cookieDomain := ".example.com"
supertokens.Init(supertokens.TypeInput{
RecipeList: []supertokens.Recipe{
session.Init(&sessmodels.TypeInput{
CookieDomain: &cookieDomain,
}),
},
})
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session
init(
app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
framework='...',
recipe_list=[
session.init(
cookie_domain='.example.com'
)
]
)
The above will set the session cookies' domain to example.com
, allowing them to be sent to *.example.com
.
note
Whilst the cookieDomain
can start with a leading .
, the value of the apiDomain
in appInfo
must point to an exact API domain only. This should be the API in which you want to expose all the auth related endpoints (for example /auth/signin
).
For local development, you should not set the cookieDomain
to an IP address based domain, or .localhost
- browsers will reject these cookies. Instead, you should alias localhost
to a named domain and use that.
#
Step 2) Set Older Cookie Domain in the Backend Config (only applicable for cookie based auth)To avoid locking out users with existing sessions (they will get a 500 error when try to refresh their session), set olderCookieDomain
to match your previous cookieDomain
. If your cookieDomain
was not set, you can use an empty string. However, if you don't have any existing sessions, you can skip this step entirely.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import SuperTokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
SuperTokens.init({
supertokens: {
connectionURI: "...",
},
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
Session.init({
cookieDomain: ".example.com",
olderCookieDomain: "" // Set to an empty string if your previous cookieDomain was unset. Otherwise, use your old cookieDomain value.
})
]
});
import (
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
cookieDomain := ".example.com"
olderCookieDomain := "" // Set to an empty string if your previous cookieDomain was unset. Otherwise, use your old cookieDomain value.
supertokens.Init(supertokens.TypeInput{
RecipeList: []supertokens.Recipe{
session.Init(&sessmodels.TypeInput{
CookieDomain: &cookieDomain,
OlderCookieDomain: &olderCookieDomain,
}),
},
})
}
from supertokens_python import init, InputAppInfo
from supertokens_python.recipe import session
init(
app_info=InputAppInfo(api_domain="...", app_name="...", website_domain="..."),
framework='...',
recipe_list=[
session.init(
cookie_domain='.example.com',
older_cookie_domain='' # Set to an empty string if your previous cookie_domain was unset. Otherwise, use your old cookie_domain value.
)
]
)
caution
If
olderCookieDomain
isn't set, users with older sessions will get a 500 error from the session refresh endpoint, effectively locking them out. This will continue untilolderCookieDomain
is set correctly or they clear their cookies.The value set for
olderCookieDomain
must be kept for 1 year because the cookie lifetime of the access token on the frontend is 1 year (even though the JWT expiry is a few hours).If you have changed the
cookieDomain
more than once within one year, to prevent a stuck state, switch to header based auth for all your clients. The important thing here is that you have to set the backend config to header even though that doc says it's optional. This is so that all clients are forced to use header based auth.Changing the
cookieDomain
can cause a temporary spike in requests, even if theolderCookieDomain
is set correctly. This happens because older sessions, with older cookie domain, require additional refresh calls to clear their old cookies and set new ones. This spike is a one-time event and should not recur after the update.
info
The olderCookieDomain
value should be set to prevent clients from having multiple session cookies from different domains. This can happen when cookies from a previous domain are still valid and sent with requests. For instance, if your previous cookieDomain
was api.example.com
and the new one is .example.com
, both sets of cookies would be sent to the apiDomain api.example.com
, leading to an inconsistent state. This can cause issues until the older cookies are cleared. Setting olderCookieDomain
in the configuration ensures that the SuperTokens SDK can automatically remove these older cookies.
#
Step 3) Frontend config (for cookie or header based auth)You need to set the same value for sessionTokenBackendDomain
on the frontend. This will allow the frontend SDK to apply interception and automatic refreshing across all your API calls:
- ReactJS
- Angular
- Vue
You will have to make changes to the auth route config, as well as to the supertokens-web-js
SDK config at the root of your application:
This change is in your auth route config.
(window as any).supertokensUIInit("supertokensui", {
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
(window as any).supertokensUISession.init({
sessionTokenBackendDomain: ".example.com"
})
]
});
This change goes in the supertokens-web-js
SDK config at the root of your application:
import SuperTokens from 'supertokens-web-js';
import Session from 'supertokens-web-js/recipe/session';
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
},
recipeList: [
Session.init({
sessionTokenBackendDomain: ".example.com"
}),
],
});
import SuperTokens from "supertokens-auth-react";
import Session from "supertokens-auth-react/recipe/session";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
Session.init({
sessionTokenBackendDomain: ".example.com"
})
]
});
You will have to make changes to the auth route config, as well as to the supertokens-web-js
SDK config at the root of your application:
This change is in your auth route config.
(window as any).supertokensUIInit("supertokensui", {
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
(window as any).supertokensUISession.init({
sessionTokenBackendDomain: ".example.com"
})
]
});
This change goes in the supertokens-web-js
SDK config at the root of your application:
import SuperTokens from 'supertokens-web-js';
import Session from 'supertokens-web-js/recipe/session';
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
},
recipeList: [
Session.init({
sessionTokenBackendDomain: ".example.com"
}),
],
});