Social / SSO login
There are different flows that the third party login provider may support:
- Flow 1) Via authorisation code (one time use code) - for web and mobile apps.
- a) If you have configred the client secret on the backend:
- The frontend sends the auth code to the backend, the backend exchanges that with the provided client secret to get the access token. The access token is then used to fetch user info and log them in.
- b) If you have not provided the client secret on the backend:
- The backend uses PKCE flow to exchange the auth code with the user's access token. The access token is then used to fetch user info and log them in.
- a) If you have configred the client secret on the backend:
- Flow 2) Via OAuth / access tokens - for mobile apps.
- The access token is available on the frontend and is sent to the backend. SuperTokens then fetches user info using the access token and logs them in.
note
The same flow applies during sign up and sign in. If the user is signing up, the createdNewUser
boolean on the frontend and backend will be true
(as the result of the sign in up API call).
- Web
- Mobile
#
Flow 1a (Sign in with Google example)#
Step 1) Redirecting to social / SSO providerThe first step is to fetch the URL on which the user will be authenticated. This can be done by querying the backend API exposed by SuperTokens (as shown below). The backend SDK automatically appends the right query params to the URL (like scope, client ID etc).
After we get the URL, we simply redirect the user there. In the code below, we will take an example of login with Google:
- Via NPM
- Via Script Tag
import { getAuthorisationURLWithQueryParamsAndSetState } from "supertokens-web-js/recipe/thirdparty";
async function googleSignInClicked() { try { const authUrl = await getAuthorisationURLWithQueryParamsAndSetState({ providerId: "google",
// This is where Google should redirect the user back after login or error. // This URL goes on the Google's dashboard as well. authorisationURL: "http://localhost:3000/auth/callback/google", });
/* Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow */
// we redirect the user to google for auth. window.location.assign(authUrl); } catch (err: any) { if (err.isSuperTokensGeneralError === true) { // this may be a custom error message sent from the API by you. window.alert(err.message); } else { window.alert("Oops! Something went wrong."); } }}
async function googleSignInClicked() { try { const authUrl = await supertokensThirdParty.getAuthorisationURLWithQueryParamsAndSetState({ providerId: "google",
// This is where Google should redirect the user back after login or error. // This URL goes on the Google's dashboard as well. authorisationURL: "http://localhost:3000/auth/callback/google", });
/* Example value of authUrl: https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&include_granted_scopes=true&response_type=code&client_id=1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com&state=5a489996a28cafc83ddff&redirect_uri=https%3A%2F%2Fsupertokens.io%2Fdev%2Foauth%2Fredirect-to-app&flowName=GeneralOAuthFlow */
// we redirect the user to google for auth. window.location.assign(authUrl); } catch (err: any) { if (err.isSuperTokensGeneralError === true) { // this may be a custom error message sent from the API by you. window.alert(err.message); } else { window.alert("Oops! Something went wrong."); } }}
#
Step 2) Handling the auth callback on your frontendOnce the third party provider redirects your user back to your app, you need to consume the information to sign in the user. This requires you to:
Setup a route in your app that will handle this callback. We recommend something like
http://localhost:3000/auth/callback/google
(for Google). Regardless of what you make this path, remember to use that same path when calling thegetAuthorisationURLWithQueryParamsAndSetState
function in the first step.On that route, call the following function on page load
- Via NPM
- Via Script Tag
import { signInAndUp } from "supertokens-web-js/recipe/thirdparty"; async function handleGoogleCallback() { try { const response = await signInAndUp(); if (response.status === "OK") { console.log(response.user) if (response.createdNewUser) { // sign up successful } else { // sign in successful } window.location.assign("/home"); } else { // SuperTokens requires that the third party provider // gives an email for the user. If that's not the case, sign up / in // will fail. // As a hack to solve this, you can override the backend functions to create a fake email for the user. window.alert("No email provided by social login. Please use another form of login"); window.location.assign("/auth"); // redirect back to login page } } catch (err: any) { if (err.isSuperTokensGeneralError === true) { // this may be a custom error message sent from the API by you. window.alert(err.message); } else { window.alert("Oops! Something went wrong."); } }}
async function handleGoogleCallback() { try { const response = await supertokensThirdParty.signInAndUp(); if (response.status === "OK") { console.log(response.user) if (response.createdNewUser) { // sign up successful } else { // sign in successful } window.location.assign("/home"); } else { // SuperTokens requires that the third party provider // gives an email for the user. If that's not the case, sign up / in // will fail. // As a hack to solve this, you can override the backend functions to create a fake email for the user. window.alert("No email provided by social login. Please use another form of login"); window.location.assign("/auth"); // redirect back to login page } } catch (err: any) { if (err.isSuperTokensGeneralError === true) { // this may be a custom error message sent from the API by you. window.alert(err.message); } else { window.alert("Oops! Something went wrong."); } }}
note
On success, the backend will send back session tokens as part of the response headers which will be automatically handled by our frontend SDK for you.
#
Special case for login with AppleUnlike other providers, Apple will not redirect your user back to your frontend app. Instead, it will redirect the user to your backend with a FORM POST
request.
Our backend SDK will capture this request and redirect the user to your frontend app on your website domain on the /auth/callback/apple
route (where /auth
is the value of websiteBasePath
set on the backend).
important
This means, that the value provided to the authorisationURL
param in step 1, will be ignored and that on the Apple developer dashboard, you should set the redirect_uri
to your API domain on the /auth/callback/apple
route (where /auth
is the value of apiBasePath
set on the backend).
#
Flow 1bcaution
Not supported by SuperTokens yet.
Flow 1a (Sign in with Apple example)
- React Native
- Android
- iOS
Step 1) Fetching the authorisation token on the frontend
This involves setting up the react-native-apple-authentication library in your app. Checkout their README
for steps on how to integrate their SDK into your application. The minimum scope required by SuperTokens is the one that gives the user's email (In case of Apple, that could be the user's actual email or the proxy email provided by Apple - it doesn't really matter).
Once the integration is done, you should call the appleAuth.performRequest
function for iOS and the appleAuthAndroid.signIn
function for Android. Either way, the result of the function will be a one time use auth code which you should send to your backend as shown in the next step.
Step 1) Fetching the authorisation token on the frontend
info
Coming Soon
info
Coming Soon
Step 2) Calling the signinup API to consume the authorisation token
Once you have the authorisation code from the auth provider, you need to call the signinup API exposed by our backend SDK as shown below:
curl --location --request POST '<YOUR_API_DOMAIN>/auth/signinup' \--header 'rid: thirdparty' \--header 'Content-Type: application/json' \--data-raw '{ "redirectURI": "...", "thirdPartyId": "apple", "code": "...", "clientId": "..."}'
important
- The
clientId
input is optional and is required only if you have initialised the same provider multiple times on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - For login with Apple on iOS, the
clientId
should be the same as your app's bundle identifier on the frontend and backend. TheredirectURI
doesn't matter and its value can be a universal link configured for your app. - On Android, the
redirectURI
should match the one configured on the Apple developer dashboard.
The response body from the API call has a status
property in it:
status: "OK"
: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user.status: "NO_EMAIL_GIVEN_BY_PROVIDER"
: This is returned if the social / SSO provider did not provider an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider.status: "GENERAL_ERROR"
: This is only possible if you have overriden the backend API to send back a custom error message which should be displayed on the frontend.
note
On success, the backend will send back session tokens as part of the response headers which will be automatically handled by our frontend SDK for you.
Flow 1b
caution
Not supported by SuperTokens yet.
Flow 2 example (Sign in with Google example)
- React Native
- Android
- iOS
Step 1) Fetching the OAuth / access tokens on the frontend
You can use the react-native-app-auth library in your app to integrate with Google and get the user's access token. The minimum scope that is required by SuperTokens is one that gives you the user's email - in case of Google login, it is "https://www.googleapis.com/auth/userinfo.email"
.
important
When setting up on the Google dashboard, you need to generate OAuth credentials for an Android application which will be used for both iOS and Android. Google does not provide a client secret in this case, so on the backend, you can give the clientSecret
config as an empty string.
Step 2) Calling the signinup API to use the OAuth tokens
Once you have the access_token
or the id_token
from the auth provider, you need to call the signinup API exposed by our backend SDK as shown below:
curl --location --request POST '<YOUR_API_DOMAIN>/auth/signinup' \--header 'rid: thirdparty' \--header 'Content-Type: application/json' \--data-raw '{ "redirectURI": "", "thirdPartyId": "apple", "authCodeResponse": { "access_token": "..." }, "clientId": "..."}'
important
- The
clientId
input is optional and is required only if you have initialised the same provider multiple times on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - In this flow, the value of
redirectURI
isn't used on the backend, so we give the API an empty string. - If you have the
id_token
, you can also just send that inplace of theaccess_token
.
The response body from the API call has a status
property in it:
status: "OK"
: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user.status: "NO_EMAIL_GIVEN_BY_PROVIDER"
: This is returned if the social / SSO provider did not provider an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider.status: "GENERAL_ERROR"
: This is only possible if you have overriden the backend API to send back a custom error message which should be displayed on the frontend.
note
On success, the backend will send back session tokens as part of the response headers which will be automatically handled by our frontend SDK for you.
For Android, Google recommends you to use their official Andoird library, which follows "Flow 1a" in these docs.
Essentially, the library will give you back a one time use auth code from Google which you can send to the /signinup
API (as shown in Flow 1a -> Step 2) to exchange it with an access token and the user's information.
important
On Google's dashboard, you should create a Web client to use for your Android app, otherwise Google won't return an access token to you.
Step 1) Fetching the OAuth / access tokens on the frontend
For iOS, you use the official guide for setting up Sign in with Google in your app. After the user successfully signs in, you can access the access token and id token from the Google signin result.
import UIKitimport GoogleSignIn
class ViewController: UIViewController { func signInWithGoogle() { let config = GIDConfiguration(clientID: "<CLIENT_ID>")
GIDSignIn.sharedInstance.signIn(with: config, presenting: self) { user, error in guard error == nil, let _user: GIDGoogleUser = user else { // Sign in failed return }
let accessToken = _user.authentication.accessToken let idToken = _user.authentication.idToken
// TODO: See next step } }}
Step 2) Calling the signinup API to use the OAuth tokens
Once you have the access_token
or the id_token
from the auth provider, you need to call the signinup API exposed by our backend SDK as shown below:
curl --location --request POST '<YOUR_API_DOMAIN>/auth/signinup' \--header 'rid: thirdparty' \--header 'Content-Type: application/json' \--data-raw '{ "redirectURI": "", "thirdPartyId": "apple", "authCodeResponse": { "access_token": "..." }, "clientId": "..."}'
important
- The
clientId
input is optional and is required only if you have initialised the same provider multiple times on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - In this flow, the value of
redirectURI
isn't used on the backend, so we give the API an empty string. - If you have the
id_token
, you can also just send that inplace of theaccess_token
.
The response body from the API call has a status
property in it:
status: "OK"
: User sign in / up was successful. The response also contains more information about the user, for example their user ID, and if it was a new user or existing user.status: "NO_EMAIL_GIVEN_BY_PROVIDER"
: This is returned if the social / SSO provider did not provider an email for the user. In this case, you want to ask the user to pick another method of sign in. Or, you can also override the backend functions to create a fake email for the user for this provider.status: "GENERAL_ERROR"
: This is only possible if you have overriden the backend API to send back a custom error message which should be displayed on the frontend.
note
On success, the backend will send back session tokens as part of the response headers which will be automatically handled by our frontend SDK for you.
#
Social / SSO login for both, web and mobile appsIf you have social / SSO login for your web and mobile app, then you might need to setup different client ID / secret for the same provider on the backend. For example, in case of Apple login, Apple gives you different client IDs for iOS login vs web & Android login (same client ID for web and Android).
In order to get this to work, you would need to call Apple.init
twice on the backend (in the providers
array). This causes an issue where when querying the signinup API, the backend would not know which client ID to use for the provider.
In order to solve this, you can:
- Provide the client ID to the API calls mentioned above; OR
- Set the
isDefault
totrue
on the backend provider config (as shown below) which means that in case the frontend doesn't pass a client ID in the signinup API call, that provider config will be used:
- NodeJS
- GoLang
- Python
import { Apple } from "supertokens-node/recipe/thirdparty";
let providers = [ // Used for web and android login. These credentials will be used // since isDefault is true, if the frontend doesn't pass a clientID to the // signinup API call, it will use this one. Apple({ isDefault: true, clientId: "...", clientSecret: { keyId: "...", privateKey: "...", teamId: "...", }, }),
// Used by iOS login. Notice that isDefault is not set here Apple({ clientId: "...", clientSecret: { keyId: "...", privateKey: "...", teamId: "...", }, }),]
import ( "github.com/supertokens/supertokens-golang/recipe/thirdparty" "github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels")
func main() { _ = []tpmodels.TypeProvider{ // Used for web and android login. These credentials will be used // since IsDefault is true, if the frontend doesn't pass a clientID to the // signinup API call, it will use this one. thirdparty.Apple(tpmodels.AppleConfig{ IsDefault: true, ClientID: "...", ClientSecret: tpmodels.AppleClientSecret{ KeyId: "...", PrivateKey: "...", TeamId: "...", }, }),
// Used by iOS login. Notice that isDefault is not set here thirdparty.Apple(tpmodels.AppleConfig{ ClientID: "...", ClientSecret: tpmodels.AppleClientSecret{ KeyId: "...", PrivateKey: "...", TeamId: "...", }, }), }}
from supertokens_python.recipe.thirdparty import Apple
providers = [ # Used for web and android login. These credentials will be used # since is_default is True, if the frontend doesn't pass a clientID to the # signinup API call, it will use this one. Apple( is_default=True, client_id="...", client_key_id="...", client_private_key="...", client_team_id="..." ),
# Used by iOS login. Notice that isDefault is not set here Apple( client_id="...", client_key_id="...", client_private_key="...", client_team_id="..." )]