Backend Setup
Let's got through the changes required so that your backend can expose the SuperTokens authentication features.
#
1. Install the SDKRun the following command in your terminal to install the package.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
npm i -s supertokens-node
go get github.com/supertokens/supertokens-golang
pip install supertokens-python
#
2. Initialize the SDKYou will have to intialize the Backend SDK alongside the code that starts your server. The init call will include configuration details for your app, how the backend will connect to the SuperTokens Core, as well as the Recipes that will be used in your setup.
- Single app setup
- Multi app setup
Add the code below to your server's init file.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
- Express
- Hapi
- Fastify
- Koa
- Loopback
- Serverless
- Next.js
- Nest.js
info
Please refer the AWS lambda, Vercel or Netlify sections (In the Integrations section on the left nav bar)
info
Please refer the NextJS section (In the Integrations section on the left nav bar)
info
Please refer the NestJS section (In the Integrations section on the left nav bar)
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "express",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "hapi",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "fastify",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "koa",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "loopback",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import (
"github.com/supertokens/supertokens-golang/recipe/emailpassword"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/thirdparty"
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
apiBasePath := "/auth"
websiteBasePath := "/auth"
err := supertokens.Init(supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "",
APIKey: "",
},
AppInfo: supertokens.AppInfo{
AppName: "<YOUR_APP_NAME>",
APIDomain: "<YOUR_API_DOMAIN>",
WebsiteDomain: "<YOUR_WEBSITE_DOMAIN>",
APIBasePath: &apiBasePath,
WebsiteBasePath: &websiteBasePath,
},
RecipeList: []supertokens.Recipe{
thirdparty.Init(&tpmodels.TypeInput{ /*TODO: See next step*/ }),
emailpassword.Init(nil),
session.Init(nil), // initializes session features
},
})
if err != nil {
panic(err.Error())
}
}
- FastAPI
- Flask
- Django
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session
init(
app_info=InputAppInfo(
app_name="<YOUR_APP_NAME>",
api_domain="<YOUR_API_DOMAIN>",
website_domain="<YOUR_WEBSITE_DOMAIN>",
api_base_path="/auth",
website_base_path="/auth"
),
supertokens_config=SupertokensConfig(
connection_uri="",
api_key=""
),
framework='fastapi',
recipe_list=[
session.init(), # initializes session features
thirdparty.init(
# TODO: See next step
),
emailpassword.init()
],
mode='asgi' # use wsgi if you are running using gunicorn
)
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session
init(
app_info=InputAppInfo(
app_name="<YOUR_APP_NAME>",
api_domain="<YOUR_API_DOMAIN>",
website_domain="<YOUR_WEBSITE_DOMAIN>",
api_base_path="/auth",
website_base_path="/auth"
),
supertokens_config=SupertokensConfig(
connection_uri="",
api_key=""
),
framework='flask',
recipe_list=[
session.init(), # initializes session features
thirdparty.init(
# TODO: See next step
),
emailpassword.init()
]
)
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session
init(
app_info=InputAppInfo(
app_name="<YOUR_APP_NAME>",
api_domain="<YOUR_API_DOMAIN>",
website_domain="<YOUR_WEBSITE_DOMAIN>",
api_base_path="/auth",
website_base_path="/auth"
),
supertokens_config=SupertokensConfig(
connection_uri="",
api_key=""
),
framework='django',
recipe_list=[
session.init(), # initializes session features
thirdparty.init(
# TODO: See next step
),
emailpassword.init()
],
mode='asgi' # use wsgi if you are running django server in sync mode
)
Add the code below to your server's init file.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
- Express
- Hapi
- Fastify
- Koa
- Loopback
- Serverless
- Next.js
- Nest.js
info
Please refer the AWS lambda, Vercel or Netlify sections (In the Integrations section on the left nav bar)
info
Please refer the NextJS section (In the Integrations section on the left nav bar)
info
Please refer the NestJS section (In the Integrations section on the left nav bar)
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "express",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/thirdpartyemailpassword/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "hapi",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "fastify",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "koa",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import EmailPassword from"supertokens-node/recipe/emailpassword";
import ThirdParty from"supertokens-node/recipe/thirdparty";
supertokens.init({
framework: "loopback",
supertokens: {
connectionURI: "",
apiKey: "",
},
appInfo: {
// learn more about this on https://supertokens.com/docs/session/appinfo
appName: "<YOUR_APP_NAME>",
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
websiteBasePath: "/auth"
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({/*TODO: See next step*/}),
Session.init() // initializes session features
]
});
import (
"github.com/supertokens/supertokens-golang/recipe/emailpassword"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/thirdparty"
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
apiBasePath := "/auth"
websiteBasePath := "/auth"
err := supertokens.Init(supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "",
APIKey: "",
},
AppInfo: supertokens.AppInfo{
AppName: "<YOUR_APP_NAME>",
APIDomain: "<YOUR_API_DOMAIN>",
WebsiteDomain: "<YOUR_WEBSITE_DOMAIN>",
APIBasePath: &apiBasePath,
WebsiteBasePath: &websiteBasePath,
},
RecipeList: []supertokens.Recipe{
thirdparty.Init(&tpmodels.TypeInput{ /*TODO: See next step*/ }),
emailpassword.Init(nil),
session.Init(nil), // initializes session features
},
})
if err != nil {
panic(err.Error())
}
}
- FastAPI
- Flask
- Django
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session
init(
app_info=InputAppInfo(
app_name="<YOUR_APP_NAME>",
api_domain="<YOUR_API_DOMAIN>",
website_domain="<YOUR_WEBSITE_DOMAIN>",
api_base_path="/auth",
website_base_path="/auth"
),
supertokens_config=SupertokensConfig(
connection_uri="",
api_key=""
),
framework='fastapi',
recipe_list=[
session.init(), # initializes session features
thirdparty.init(
# TODO: See next step
),
emailpassword.init()
],
mode='asgi' # use wsgi if you are running using gunicorn
)
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session
init(
app_info=InputAppInfo(
app_name="<YOUR_APP_NAME>",
api_domain="<YOUR_API_DOMAIN>",
website_domain="<YOUR_WEBSITE_DOMAIN>",
api_base_path="/auth",
website_base_path="/auth"
),
supertokens_config=SupertokensConfig(
connection_uri="",
api_key=""
),
framework='flask',
recipe_list=[
session.init(), # initializes session features
thirdparty.init(
# TODO: See next step
),
emailpassword.init()
]
)
from supertokens_python import init, InputAppInfo, SupertokensConfig
from supertokens_python.recipe import thirdparty, emailpassword, session
init(
app_info=InputAppInfo(
app_name="<YOUR_APP_NAME>",
api_domain="<YOUR_API_DOMAIN>",
website_domain="<YOUR_WEBSITE_DOMAIN>",
api_base_path="/auth",
website_base_path="/auth"
),
supertokens_config=SupertokensConfig(
connection_uri="",
api_key=""
),
framework='django',
recipe_list=[
session.init(), # initializes session features
thirdparty.init(
# TODO: See next step
),
emailpassword.init()
],
mode='asgi' # use wsgi if you are running django server in sync mode
)
#
3. Initialise Social Login ProvidersPopulate the providers
array with the third party auth providers you want.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import SuperTokens from "supertokens-node";
import ThirdParty from "supertokens-node/recipe/thirdparty"
import EmailPassword from "supertokens-node/recipe/emailpassword"
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "...",
},
recipeList: [
EmailPassword.init(),
ThirdParty.init({
// We have provided you with development keys which you can use for testing.
// IMPORTANT: Please replace them with your own OAuth keys for production use.
signInAndUpFeature: {
providers: [{
config: {
thirdPartyId: "google",
clients: [{
clientId: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
clientSecret: "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"
}]
}
}, {
config: {
thirdPartyId: "github",
clients: [{
clientId: "467101b197249757c71f",
clientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd"
}]
}
}, {
config: {
thirdPartyId: "apple",
clients: [{
clientId: "4398792-io.supertokens.example.service",
additionalConfig: {
keyId: "7M48Y4RYDL",
privateKey:
"-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
teamId: "YWQCXGJRJL",
}
}]
}
}],
}
}),
// ...
]
});
import (
"github.com/supertokens/supertokens-golang/recipe/thirdparty"
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
)
func main() {
// Inside supertokens.Init -> RecipeList
thirdparty.Init(&tpmodels.TypeInput{
SignInAndUpFeature: tpmodels.TypeInputSignInAndUp{
Providers: []tpmodels.ProviderInput{
// We have provided you with development keys which you can use for testing.
// IMPORTANT: Please replace them with your own OAuth keys for production use.
{
Config: tpmodels.ProviderConfig{
ThirdPartyId: "google",
Clients: []tpmodels.ProviderClientConfig{
{
ClientID: "1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
ClientSecret: "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",
},
},
},
},
{
Config: tpmodels.ProviderConfig{
ThirdPartyId: "github",
Clients: []tpmodels.ProviderClientConfig{
{
ClientID: "467101b197249757c71f",
ClientSecret: "e97051221f4b6426e8fe8d51486396703012f5bd",
},
},
},
},
{
Config: tpmodels.ProviderConfig{
ThirdPartyId: "apple",
Clients: []tpmodels.ProviderClientConfig{
{
ClientID: "4398792-io.supertokens.example.service",
AdditionalConfig: map[string]interface{}{
"keyId": "7M48Y4RYDL",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
"teamId": "YWQCXGJRJL",
},
},
},
},
},
},
},
})
}
from supertokens_python.recipe.thirdparty.provider import ProviderInput, ProviderConfig, ProviderClientConfig
from supertokens_python.recipe import thirdparty
# Inside init
thirdparty.init(
sign_in_and_up_feature=thirdparty.SignInAndUpFeature(
providers=[
# We have provided you with development keys which you can use for testing.
# IMPORTANT: Please replace them with your own OAuth keys for production use.
ProviderInput(
config=ProviderConfig(
third_party_id="google",
clients=[
ProviderClientConfig(
client_id="1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com",
client_secret="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",
),
],
),
),
ProviderInput(
config=ProviderConfig(
third_party_id="github",
clients=[
ProviderClientConfig(
client_id='467101b197249757c71f',
client_secret='e97051221f4b6426e8fe8d51486396703012f5bd'
),
],
),
),
ProviderInput(
config=ProviderConfig(
third_party_id="apple",
clients=[
ProviderClientConfig(
client_id="4398792-io.supertokens.example.service",
additional_config={
"keyId": "7M48Y4RYDL",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgu8gXs+XYkqXD6Ala9Sf/iJXzhbwcoG5dMh1OonpdJUmgCgYIKoZIzj0DAQehRANCAASfrvlFbFCYqn3I2zeknYXLwtH30JuOKestDbSfZYxZNMqhF/OzdZFTV0zc5u5s3eN+oCWbnvl0hM+9IW0UlkdA\n-----END PRIVATE KEY-----",
"teamId": "YWQCXGJRJL"
},
),
],
),
),
]
)
)
When you want to generate your own keys, please refer to the corresponding documentation to get your client ids and client secrets for each of the below providers:
- Generate your client ID and secret by following the docs here
- Set the authorisation callback URL to
<YOUR_WEBSITE_DOMAIN>/auth/callback/google
Github
- Generate your client ID and secret by following the docs here
- Set the authorisation callback URL to
<YOUR_WEBSITE_DOMAIN>/auth/callback/github
Apple
- Generate your client ID and secret by following this article
- Set the authorisation callback URL to
<YOUR_API_DOMAIN>/auth/callback/apple
. Note that Apple doesn't allowlocalhost
in the URL. So if you are in dev mode, you can use the dev keys we have provided above.
important
You can find the list of built in providers here. To add a provider that is not listed, you can follow our guide on setting up custom providers.
#
4. Add the SuperTokens APIs and Configure CORSNow that the SDK is initialized you need to expose the endpoints that will be used by the frontend SDKs. Besides this, your server's CORS, Cross-Origin Resource Sharing, settings should be updated to allow the use of the authentication headers required by SuperTokens.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
- Express
- Hapi
- Fastify
- Koa
- Loopback
- Serverless
- Next.js
- Nest.js
info
Please refer the AWS lambda, Vercel or Netlify sections (In the Integrations section on the left nav bar)
info
Please refer the NextJS section (In the Integrations section on the left nav bar)
info
Please refer the NestJS section (In the Integrations section on the left nav bar)
important
- Add the
middleware
BEFORE all your routes. - Add the
cors
middleware BEFORE the SuperTokens middleware as shown below.
import express from "express";
import cors from "cors";
import supertokens from "supertokens-node";
import { middleware } from "supertokens-node/framework/express";
let app = express();
app.use(cors({
origin: "<YOUR_WEBSITE_DOMAIN>",
allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()],
credentials: true,
}));
// IMPORTANT: CORS should be before the below line.
app.use(middleware());
// ...your API routes
Register the plugin
.
import Hapi from "@hapi/hapi";
import supertokens from "supertokens-node";
import { plugin } from "supertokens-node/framework/hapi";
let server = Hapi.server({
port: 8000,
routes: {
cors: {
origin: ["<YOUR_WEBSITE_DOMAIN>"],
additionalHeaders: [...supertokens.getAllCORSHeaders()],
credentials: true,
}
}
});
(async () => {
await server.register(plugin);
await server.start();
})();
// ...your API routes
Register the plugin
. Also register @fastify/formbody
plugin.
import cors from "@fastify/cors";
import supertokens from "supertokens-node";
import { plugin } from "supertokens-node/framework/fastify";
import formDataPlugin from "@fastify/formbody";
import fastifyImport from "fastify";
let fastify = fastifyImport();
// ...other middlewares
fastify.register(cors, {
origin: "<YOUR_WEBSITE_DOMAIN>",
allowedHeaders: ['Content-Type', ...supertokens.getAllCORSHeaders()],
credentials: true,
});
(async () => {
await fastify.register(formDataPlugin);
await fastify.register(plugin);
await fastify.listen(8000);
})();
// ...your API routes
important
Add the middleware
BEFORE all your routes.
import Koa from "koa";
import cors from '@koa/cors';
import supertokens from "supertokens-node";
import { middleware } from "supertokens-node/framework/koa";
let app = new Koa();
app.use(cors({
origin: "<YOUR_WEBSITE_DOMAIN>",
allowHeaders: ["content-type", ...supertokens.getAllCORSHeaders()],
credentials: true,
}));
app.use(middleware());
// ...your API routes
important
Add the middleware
BEFORE all your routes.
import { RestApplication } from "@loopback/rest";
import supertokens from "supertokens-node";
import { middleware } from "supertokens-node/framework/loopback";
let app = new RestApplication({
rest: {
cors: {
origin: "<YOUR_WEBSITE_DOMAIN>",
allowedHeaders: ["content-type", ...supertokens.getAllCORSHeaders()],
credentials: true
}
}
});
app.middleware(middleware);
// ...your API routes
- Chi
- net/http
- Gin
- Mux
Use the supertokens.Middleware
and the supertokens.GetAllCORSHeaders()
functions as shown below.
import (
"net/http"
"strings"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
// SuperTokens init...
http.ListenAndServe("SERVER ADDRESS", corsMiddleware(
supertokens.Middleware(http.HandlerFunc(func(rw http.ResponseWriter,
r *http.Request) {
// TODO: Handle your APIs..
}))))
}
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(response http.ResponseWriter, r *http.Request) {
response.Header().Set("Access-Control-Allow-Origin", "<YOUR_WEBSITE_DOMAIN>")
response.Header().Set("Access-Control-Allow-Credentials", "true")
if r.Method == "OPTIONS" {
// we add content-type + other headers used by SuperTokens
response.Header().Set("Access-Control-Allow-Headers",
strings.Join(append([]string{"Content-Type"},
supertokens.GetAllCORSHeaders()...), ","))
response.Header().Set("Access-Control-Allow-Methods", "*")
response.Write([]byte(""))
} else {
next.ServeHTTP(response, r)
}
})
}
Use the supertokens.Middleware
and the supertokens.GetAllCORSHeaders()
functions as shown below.
import (
"net/http"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
// SuperTokens init...
router := gin.New()
// CORS
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"<YOUR_WEBSITE_DOMAIN>"},
AllowMethods: []string{"GET", "POST", "DELETE", "PUT", "OPTIONS"},
AllowHeaders: append([]string{"content-type"},
supertokens.GetAllCORSHeaders()...),
AllowCredentials: true,
}))
// Adding the SuperTokens middleware
router.Use(func(c *gin.Context) {
supertokens.Middleware(http.HandlerFunc(
func(rw http.ResponseWriter, r *http.Request) {
c.Next()
})).ServeHTTP(c.Writer, c.Request)
// we call Abort so that the next handler in the chain is not called, unless we call Next explicitly
c.Abort()
})
// Add APIs and start server
}
Use the supertokens.Middleware
and the supertokens.GetAllCORSHeaders()
functions as shown below.
import (
"github.com/go-chi/chi"
"github.com/go-chi/cors"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
// SuperTokens init...
r := chi.NewRouter()
// CORS
r.Use(cors.Handler(cors.Options{
AllowedOrigins: []string{"<YOUR_WEBSITE_DOMAIN>"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: append([]string{"Content-Type"},
supertokens.GetAllCORSHeaders()...),
AllowCredentials: true,
}))
// SuperTokens Middleware
r.Use(supertokens.Middleware)
// Add APIs and start server
}
Use the supertokens.Middleware
and the supertokens.GetAllCORSHeaders()
functions as shown below.
import (
"net/http"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/supertokens/supertokens-golang/supertokens"
)
func main() {
// SuperTokens init...
// TODO: Add APIs
router := mux.NewRouter()
// Adding handlers.CORS(options)(supertokens.Middleware(router)))
http.ListenAndServe("SERVER ADDRESS", handlers.CORS(
handlers.AllowedHeaders(append([]string{"Content-Type"},
supertokens.GetAllCORSHeaders()...)),
handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "OPTIONS"}),
handlers.AllowedOrigins([]string{"<YOUR_WEBSITE_DOMAIN>"}),
handlers.AllowCredentials(),
)(supertokens.Middleware(router)))
}
- FastAPI
- Flask
- Django
Use the Middleware
(BEFORE all your routes) and the get_all_cors_headers()
functions as shown below.
from supertokens_python import get_all_cors_headers
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from supertokens_python.framework.fastapi import get_middleware
app = FastAPI()
app.add_middleware(get_middleware())
# TODO: Add APIs
app.add_middleware(
CORSMiddleware,
allow_origins=[
"<YOUR_WEBSITE_DOMAIN>"
],
allow_credentials=True,
allow_methods=["GET", "PUT", "POST", "DELETE", "OPTIONS", "PATCH"],
allow_headers=["Content-Type"] + get_all_cors_headers(),
)
# TODO: start server
- Use the
Middleware
(BEFORE all your routes and after calling init function) and theget_all_cors_headers()
functions as shown below. - Add a route to catch all paths and return a 404. This is needed because if we don't add this, then OPTIONS request for the APIs exposed by the
Middleware
will return a404
.
from supertokens_python import get_all_cors_headers
from flask import Flask, abort
from flask_cors import CORS
from supertokens_python.framework.flask import Middleware
app = Flask(__name__)
Middleware(app)
# TODO: Add APIs
CORS(
app=app,
origins=[
"<YOUR_WEBSITE_DOMAIN>"
],
supports_credentials=True,
allow_headers=["Content-Type"] + get_all_cors_headers(),
)
# This is required since if this is not there, then OPTIONS requests for
# the APIs exposed by the supertokens' Middleware will return a 404
@app.route('/', defaults={'u_path': ''})
@app.route('/<path:u_path>')
def catch_all(u_path: str):
abort(404)
# TODO: start server
Use the Middleware
and the get_all_cors_headers()
functions as shown below in your settings.py
.
from supertokens_python import get_all_cors_headers
from typing import List
from corsheaders.defaults import default_headers
CORS_ORIGIN_WHITELIST = [
"<YOUR_WEBSITE_DOMAIN>"
]
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
"<YOUR_WEBSITE_DOMAIN>"
]
CORS_ALLOW_HEADERS: List[str] = list(default_headers) + [
"Content-Type"
] + get_all_cors_headers()
INSTALLED_APPS = [
'corsheaders',
'supertokens_python'
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...,
'supertokens_python.framework.django.django_middleware.middleware',
]
# TODO: start server
You can review all the endpoints that are added through the use of SuperTokens by visiting the API Specs.
#
5. Add the SuperTokens Error HandlerDepending on the language and framework that you are using, you might need to add a custom error handler to your server. The handler will catch all the authentication related errors and return proper HTTP responses that can be parsed by the frontend SDKs.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
- Express
- Hapi
- Fastify
- Koa
- Loopback
- Serverless
- Next.js
- Nest.js
info
Please refer the AWS lambda, Vercel or Netlify sections (In the Integrations section on the left nav bar)
info
Please refer the NextJS section (In the Integrations section on the left nav bar)
info
Please refer the NestJS section (In the Integrations section on the left nav bar)
import express, { Request, Response, NextFunction } from 'express';
import { errorHandler } from "supertokens-node/framework/express";
let app = express();
// ...your API routes
// Add this AFTER all your routes
app.use(errorHandler())
// your own error handler
app.use((err: unknown, req: Request, res: Response, next: NextFunction) => { /* ... */ });
No additional errorHandler
is required.
Add the errorHandler
Before all your routes and plugin registration
import Fastify from "fastify";
import { errorHandler } from "supertokens-node/framework/fastify";
let fastify = Fastify();
fastify.setErrorHandler(errorHandler());
// ...your API routes
No additional errorHandler
is required.
No additional errorHandler
is required.
info
You can skip this step
info
You can skip this step
#
6. Secure Application RoutesNow that your server can authenticate users, the final step that you need to take care of is to prevent unauthorized access to certain parts of the application.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
For your APIs that require a user to be logged in, use the verifySession
middleware.
- Express
- Hapi
- Fastify
- Koa
- Loopback
- Serverless
- Next.js
- Nest.js
info
Please refer the AWS lambda, Vercel or Netlify sections (In the Integrations section on the left nav bar)
info
Please refer the NextJS section (In the Integrations section on the left nav bar)
info
Please refer the NestJS section (In the Integrations section on the left nav bar)
import express from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import { SessionRequest } from "supertokens-node/framework/express";
let app = express();
app.post("/like-comment", verifySession(), (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
//....
});
import Hapi from "@hapi/hapi";
import { verifySession } from "supertokens-node/recipe/session/framework/hapi";
import { SessionRequest } from "supertokens-node/framework/hapi";
let server = Hapi.server({ port: 8000 });
server.route({
path: "/like-comment",
method: "post",
options: {
pre: [
{
method: verifySession()
},
],
},
handler: async (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
//...
}
})
import Fastify from "fastify";
import { verifySession } from "supertokens-node/recipe/session/framework/fastify";
import { SessionRequest } from "supertokens-node/framework/fastify";
let fastify = Fastify();
fastify.post("/like-comment", {
preHandler: verifySession(),
}, (req: SessionRequest, res) => {
let userId = req.session!.getUserId();
//....
});
import KoaRouter from "koa-router";
import { verifySession } from "supertokens-node/recipe/session/framework/koa";
import { SessionContext } from "supertokens-node/framework/koa";
let router = new KoaRouter();
router.post("/like-comment", verifySession(), (ctx: SessionContext, next) => {
let userId = ctx.session!.getUserId();
//....
});
import { inject, intercept } from "@loopback/core";
import { RestBindings, MiddlewareContext, post, response } from "@loopback/rest";
import { verifySession } from "supertokens-node/recipe/session/framework/loopback";
import { SessionContext } from "supertokens-node/framework/loopback";
class LikeComment {
constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) { }
@post("/like-comment")
@intercept(verifySession())
@response(200)
handler() {
let userId = (this.ctx as SessionContext).session!.getUserId();
//....
}
}
For your APIs that require a user to be logged in, use the VerifySession
middleware.
- Chi
- net/http
- Gin
- Mux
import (
"fmt"
"net/http"
"github.com/supertokens/supertokens-golang/recipe/session"
)
func main() {
_ = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// Wrap the API handler in session.VerifySession
session.VerifySession(nil, likeCommentAPI).ServeHTTP(rw, r)
})
}
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(r.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/supertokens/supertokens-golang/recipe/session"
"github.com/supertokens/supertokens-golang/recipe/session/sessmodels"
)
func main() {
router := gin.New()
// Wrap the API handler in session.VerifySession
router.POST("/likecomment", verifySession(nil), likeCommentAPI)
}
// This is a function that wraps the supertokens verification function
// to work the gin
func verifySession(options *sessmodels.VerifySessionOptions) gin.HandlerFunc {
return func(c *gin.Context) {
session.VerifySession(options, func(rw http.ResponseWriter, r *http.Request) {
c.Request = c.Request.WithContext(r.Context())
c.Next()
})(c.Writer, c.Request)
// we call Abort so that the next handler in the chain is not called, unless we call Next explicitly
c.Abort()
}
}
func likeCommentAPI(c *gin.Context) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(c.Request.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
import (
"fmt"
"net/http"
"github.com/go-chi/chi"
"github.com/supertokens/supertokens-golang/recipe/session"
)
func main() {
r := chi.NewRouter()
// Wrap the API handler in session.VerifySession
r.Post("/likecomment", session.VerifySession(nil, likeCommentAPI))
}
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(r.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/supertokens/supertokens-golang/recipe/session"
)
func main() {
router := mux.NewRouter()
// Wrap the API handler in session.VerifySession
router.HandleFunc("/likecomment", session.VerifySession(nil, likeCommentAPI)).Methods(http.MethodPost)
}
func likeCommentAPI(w http.ResponseWriter, r *http.Request) {
// retrieve the session object as shown below
sessionContainer := session.GetSessionFromRequestContext(r.Context())
userID := sessionContainer.GetUserID()
fmt.Println(userID)
}
For your APIs that require a user to be logged in, use the verify_session
middleware.
- FastAPI
- Flask
- Django
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
@app.post('/like_comment')
async def like_comment(session: SessionContainer = Depends(verify_session())):
user_id = session.get_user_id()
print(user_id)
from supertokens_python.recipe.session.framework.flask import verify_session
from supertokens_python.recipe.session import SessionContainer
from flask import g
@app.route('/update-jwt', methods=['POST'])
@verify_session()
def like_comment():
session: SessionContainer = g.supertokens
user_id = session.get_user_id()
print(user_id)
from supertokens_python.recipe.session.framework.django.asyncio import verify_session
from django.http import HttpRequest
from supertokens_python.recipe.session import SessionContainer
@verify_session()
async def like_comment(request: HttpRequest):
session: SessionContainer = request.supertokens
user_id = session.get_user_id()
print(user_id)
The middleware function returns a 401
to the frontend if a session doesn't exist, or if the access token has expired, in which case, our frontend SDK automatically refreshes the session.
In case of successful session verification, you get access to a session
object using which you can get the user's ID, or manipulate the session information.
#
7. Test the Login FlowNow that you have configured both the frontend and the backend, you can return to the frontend login page. From here follow these steps to confirm that your setup is working properly.
- Click on the Sign up button to create a new account.
- After you have created the account go to Login page and fill in your credentials.
- If you are greeted with the login screen you have completed the quickstart setup.
๐ Congratulations ๐
You've successfully integrated SuperTokens with your existing application!
Of course, there are additional things that you should add in order to provide a complete authentication experience. We will talk about those things in the next section.