Social 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: Authorization code grant flow (Sign in with Google example)
Step 1) Redirecting to social / SSO provider
The 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 { getThirdPartyAuthorisationURLWithQueryParamsAndSetState } from "supertokens-web-js/recipe/thirdpartypasswordless";
async function googleSignInClicked() {
try {
const authUrl = await getThirdPartyAuthorisationURLWithQueryParamsAndSetState({
thirdPartyId: "google",
// This is where Google should redirect the user back after login or error.
// This URL goes on the Google's dashboard as well.
frontendRedirectURI: "http://<YOUR_WEBSITE_DOMAIN>/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 supertokensThirdPartyPasswordless.getThirdPartyAuthorisationURLWithQueryParamsAndSetState({
thirdPartyId: "google",
// This is where Google should redirect the user back after login or error.
// This URL goes on the Google's dashboard as well.
frontendRedirectURI: "http://<YOUR_WEBSITE_DOMAIN>/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 frontend
Once 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://<YOUR_WEBSITE_DOMAIN>/auth/callback/google
(for Google). Regardless of what you make this path, remember to use that same path when calling thegetThirdPartyAuthorisationURLWithQueryParamsAndSetState
function in the first step.On that route, call the following function on page load
- Via NPM
- Via Script Tag
import { thirdPartySignInAndUp } from "supertokens-web-js/recipe/thirdpartypasswordless";
async function handleGoogleCallback() {
try {
const response = await thirdPartySignInAndUp();
if (response.status === "OK") {
console.log(response.user)
if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) {
// sign up successful
} else {
// sign in successful
}
window.location.assign("/home");
} else if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
// this can happen due to automatic account linking. Please see our account linking docs
} 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 supertokensThirdPartyPasswordless.thirdPartySignInAndUp();
if (response.status === "OK") {
console.log(response.user)
if (response.createdNewRecipeUser && response.user.loginMethods.length === 1) {
// sign up successful
} else {
// sign in successful
}
window.location.assign("/home");
} else if (response.status === "SIGN_IN_UP_NOT_ALLOWED") {
// this can happen due to automatic account linking. Please see our account linking docs
} 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 Apple
Unlike 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. This means that the URL that you configure on the Apple's dashboard should point to your backend API layer in which our middleware will handle the request and redirect the user to your frontend app. Your frontend app should then call the thirdPartySignInAndUp
API on that page as shown previously.
In order to tell SuperTokens which frontend route to redirect the user back to, you need to set the frontendRedirectURI
to the frontend route (just like for other providers), and also need to set the redirectURIOnProviderDashboard
to point to your backend API route (to which Apple will send a POST request).
- Via NPM
- Via Script Tag
import { getThirdPartyAuthorisationURLWithQueryParamsAndSetState } from "supertokens-web-js/recipe/thirdpartypasswordless";
async function appleSignInClicked() {
try {
const authUrl = await getThirdPartyAuthorisationURLWithQueryParamsAndSetState({
thirdPartyId: "apple",
frontendRedirectURI: "http://localhost:3000/auth/callback/apple", // This is an example callback URL on your frontend. You can use another path as well.
redirectURIOnProviderDashboard: "<YOUR_API_DOMAIN>/auth/callback/apple", // This URL goes on the Apple's dashboard
});
// we redirect the user to apple 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 appleSignInClicked() {
try {
const authUrl = await supertokensThirdPartyPasswordless.getThirdPartyAuthorisationURLWithQueryParamsAndSetState({
thirdPartyId: "apple",
frontendRedirectURI: "http://localhost:3000/auth/callback/apple", // This is an example callback URL on your frontend. You can use another path as well.
redirectURIOnProviderDashboard: "<YOUR_API_DOMAIN>/auth/callback/apple", // This URL goes on the Apple's dashboard
});
/*
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.");
}
}
}
Flow 1b: Authorization code grant flow with PKCE
This is identical to flow 1a, except that you do not need to provide a client secret during backend init. This flow only works for providers which support the PKCE flow.
Flow 2: Via OAuth / Access token
caution
This flow is not applicable for web apps.
Flow 1a: Authorization code grant flow (Sign in with Apple example)
- React Native
- Android
- iOS
- Flutter
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
Step 1) Fetching the authorisation token on the frontend
For iOS you use the normal sign in with apple flow and then use the id token to login with SuperTokens
import UIKit
import AuthenticationServices
class ViewController: UIViewController, ASAuthorizationControllerPresentationContextProviding, ASAuthorizationControllerDelegate {
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return view.window!
}
func loginWithApple() {
let authorizationRequest = ASAuthorizationAppleIDProvider().createRequest()
authorizationRequest.requestedScopes = [.email, .fullName]
let authorizationController = ASAuthorizationController(authorizationRequests: [authorizationRequest])
authorizationController.presentationContextProvider = self
authorizationController.delegate = self
authorizationController.performRequests()
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
guard let credential: ASAuthorizationAppleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential,
let authorizationCode = credential.authorizationCode,
let authorizationCodeString: String = String(data: authorizationCode, encoding: .utf8),
let email: String = credential.email as? String,
let nameComponents: PersonNameComponents = credential.fullName as? PersonNameComponents,
let firstName: String = nameComponents.givenName as? String,
let lastName: String = nameComponents.familyName as? String else {return}
// Send the user information and auth code to the backend. Refer to the next step.
}
}
Step 1) Fetching the authorisation token on the frontend
For flutter we use the sign_in_with_apple package, make sure to follow the prerequisites steps to get the package setup. After setup use the snippet below to trigger the apple sign in flow.
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
void loginWithApple() async {
try {
var credential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
// Required for Android only
webAuthenticationOptions: WebAuthenticationOptions(
clientId: "<CLIENT_ID>",
redirectUri: Uri.parse(
"<API_DOMAIN>/<API_BASE_PATH>/callback/apple",
),
),
);
String authorizationCode = credential.authorizationCode;
String? idToken = credential.identityToken;
String? email = credential.email;
String? firstname = credential.givenName;
String? lastName = credential.familyName;
// Send the user information and auth code to the backend. Refer to the next step.
} catch (e) {
// Sign in aborted or failed
}
}
In the snippet above for Android we need to pass an additional webAuthenticationOptions
property when signing in with Apple. This is because on Android the library uses the web login flow and we need to provide it with the client id and redirection uri. The redirectUri
property here is the URL to which Apple will make a POST
request after the user has logged in. The SuperTokens backend SDKs provide an API for this at <API_DOMAIN>/<API_BASE_PATH>/callback/apple
.
Additional steps for Android
For android we also need to provide a way for the web login flow to redirect back to the app. By default the API provided by the backend SDKs redirect to the website domain you provide when initialising the SDK, we can override the API to have it redirect to our app instead. For example if you were using the Node.js SDK:
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import ThirdPartyPasswordless from "supertokens-node/recipe/thirdpartypasswordless";
ThirdPartyPasswordless.init({
override: {
apis: (original) => {
return {
...original,
appleRedirectHandlerPOST: async (input) => {
if (original.appleRedirectHandlerPOST === undefined) {
throw Error("Should never come here");
}
// inut.formPostInfoFromProvider contains all the query params attached by Apple
const stateInBase64 = input.formPostInfoFromProvider.state;
// The web SDKs add a default state
if (stateInBase64 === undefined) {
// Redirect to android app
// We create a dummy URL to create the query string
const dummyUrl = new URL("http://localhost:8080");
for (const [key, value] of Object.entries(input.formPostInfoFromProvider)) {
dummyUrl.searchParams.set(key, `${value}`);
}
const queryString = dummyUrl.searchParams.toString();
// Refer to the README of sign_in_with_apple to understand what this url is
const redirectUrl = `intent://callback?${queryString}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end`;
input.options.res.setHeader("Location", redirectUrl, false);
input.options.res.setStatusCode(303);
input.options.res.sendHTMLResponse("");
} else {
// For the web flow we can use the original implementation
original.appleRedirectHandlerPOST(input);
}
},
};
},
},
})
import (
"net/http"
"strings"
"github.com/supertokens/supertokens-golang/recipe/thirdpartypasswordless"
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
"github.com/supertokens/supertokens-golang/recipe/thirdpartypasswordless/tplmodels"
)
func main() {
thirdpartypasswordless.Init(tplmodels.TypeInput{
Override: &tplmodels.OverrideStruct{
APIs: func(originalImplementation tplmodels.APIInterface) tplmodels.APIInterface {
originalAppleRedirectPost := *originalImplementation.AppleRedirectHandlerPOST
*originalImplementation.AppleRedirectHandlerPOST = func(formPostInfoFromProvider map[string]interface{}, options tpmodels.APIOptions, userContext *map[string]interface{}) error {
// formPostInfoFromProvider contains all the query params attached by Apple
state, stateOk := formPostInfoFromProvider["state"].(string)
queryParams := []string{}
if (!stateOk) || state == "" {
// Redirect to android app
for key, value := range formPostInfoFromProvider {
queryParams = append(queryParams, key+"="+value.(string))
}
queryString := ""
if len(queryParams) > 0 {
queryString = strings.Join(queryParams, "&")
}
// Refer to the README of sign_in_with_apple to understand what this url is
redirectUri := "intent://callback?" + queryString + "#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end"
options.Res.Header().Set("Location", redirectUri)
options.Res.WriteHeader(http.StatusSeeOther)
return nil
} else {
return originalAppleRedirectPost(formPostInfoFromProvider, options, userContext)
}
}
return originalImplementation
},
},
Providers: []tpmodels.ProviderInput{
// ...
},
})
}
from supertokens_python.recipe import thirdpartypasswordless
from supertokens_python.recipe.thirdpartypasswordless.interfaces import APIInterface, ThirdPartyAPIOptions
from typing import Dict, Any
def override_thirdparty_apis(original_implementation: APIInterface):
original_apple_redirect_post = original_implementation.apple_redirect_handler_post
async def apple_redirect_handler_post(
form_post_info: Dict[str, Any],
api_options: ThirdPartyAPIOptions,
user_context: Dict[str, Any]
):
# form_post_info contains all the query params attached by Apple
state = form_post_info["state"]
# The web SDKs add a default state
if state is None:
query_items = [
f"{key}={value}" for key, value in form_post_info.items()
]
query_string = "&".join(query_items)
# Refer to the README of sign_in_with_apple to understand what this url is
redirect_url = f"intent://callback?${query_string}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end"
api_options.response.set_header("Location", redirect_url)
api_options.response.set_status_code(303)
api_options.response.set_html_content("")
else:
return await original_apple_redirect_post(form_post_info, api_options, user_context)
original_implementation.apple_redirect_handler_post = apple_redirect_handler_post
return original_implementation
thirdpartypasswordless.init(
override=thirdpartypasswordless.InputOverrideConfig(
apis=override_thirdparty_apis
),
flow_type="USER_INPUT_CODE",
)
In the code above we override the appleRedirectHandlerPOST
API to check if the request was made by our Android app (You can skip checking the state if you only have a mobile app and no website). sign_in_with_apple
requires us to parse the query params sent by apple and include them in the redirect URL in a specific way, and then we simply redirect to the deep link url. Refer to the README for sign_in_with_apple
to read about the deep link setup required in Android.
Step 2) Calling the signinup API to consume the authorisation token
- Single tenant setup
- Multi tenant setup
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: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "apple",
"clientType": "...",
"redirecURIInfo": {
"redirectURIOnProviderDashboard": "<YOUR_API_DOMAIN>/auth/callback/apple",
"redirectURIQueryParams": {
"code": "...",
"user": {
"name":{
"firstName":"...",
"lastName":"..."
},
"email":"..."
}
}
}
}'
important
- On iOS, the client id set in the backend should be the same as the bundle identifier for your app.
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - On iOS,
redirectURIOnProviderDashboard
doesn't matter and its value can be a universal link configured for your app. - On Android, the
redirectURIOnProviderDashboard
should match the one configured on the Apple developer dashboard. - The
user
object contains information provided by Apple.
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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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.
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/<TENANT_ID>/signinup' \
--header 'rid: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "apple",
"clientType": "...",
"redirecURIInfo": {
"redirectURIOnProviderDashboard": "<YOUR_API_DOMAIN>/auth/<TENANT_ID>/callback/apple",
"redirectURIQueryParams": {
"code": "...",
"user": {
"name":{
"firstName":"...",
"lastName":"..."
},
"email":"..."
}
}
}
}'
important
- On iOS, the client id set in the backend should be the same as the bundle identifier for your app.
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - On iOS,
redirectURIOnProviderDashboard
doesn't matter and its value can be a universal link configured for your app. - On Android, the
redirectURIOnProviderDashboard
should match the one configured on the Apple developer dashboard. - The
user
object contains information provided by Apple.
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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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: Authorization code grant flow with PKCE
This is similar to flow 1a, except that you do not need to provide a client secret during backend init. This flow only works for providers which support the PKCE flow.
- React Native
- Android
- iOS
- Flutter
Step 1) Fetching the authorisation token on the frontend
See the setup step for this in flow 1a. In addition to that, you need to configure the react native auth library to also return the PKCE code verifier along with the authorization code. This can be done by setting the usePKCE
boolean to true
and also by setting the skipCodeExchange
to true
when configuring the react native auth library.
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"
.
Step 1) Fetching the authorisation token on the frontend
You can follow the official guide on how to use the PKCE flow with google sign in on Android
Step 1) Fetching the authorisation token on the frontend
You can follow the official guide on how to use the PKCE flow with google sign in on iOS
Step 1) Fetching the authorisation token on the frontend
You can follow the guide for flutter_appauth on how to use the PKCE flow with google sign in with Flutter
Step 2) Calling the signinup API to consume the authorisation token
- Single tenant setup
- Multi tenant setup
Once you have the authorisation code and PKCE verifier 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: thirdpartypasswordless' \
--header 'Content-Type: application/json' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"redirectURIInfo": {
"redirectURIOnProviderDashboard": "<YOUR_API_DOMAIN>/auth/callback/google",
"redirectURIQueryParams": {
"code": "...",
},
"pkceCodeVerifier": "..."
}
}'
important
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - On iOS,
redirectURIOnProviderDashboard
doesn't matter and its value can be a universal link configured for your app. - On Android, the
redirectURIOnProviderDashboard
should match the one configured on the Google cloud platform.
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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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.
Once you have the authorisation code and PKCE verifier 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/<TENANT_ID>/signinup' \
--header 'rid: thirdpartypasswordless' \
--header 'Content-Type: application/json' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"redirectURIInfo": {
"redirectURIOnProviderDashboard": "<YOUR_API_DOMAIN>/auth/<TENANT_ID>/callback/google",
"redirectURIQueryParams": {
"code": "...",
},
"pkceCodeVerifier": "..."
}
}'
important
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - On iOS,
redirectURIOnProviderDashboard
doesn't matter and its value can be a universal link configured for your app. - On Android, the
redirectURIOnProviderDashboard
should match the one configured on the Google cloud platform.
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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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 2: Via OAuth / Access token (Sign in with Google example)
- React Native
- Android
- iOS
- Flutter
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 omit the clientSecret
config in the clients
array.
Step 2) Calling the signinup API to use the OAuth tokens
- Single tenant setup
- Multi tenant setup
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: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"oAuthTokens": {
"access_token": "..."
},
}'
important
- If you don't have the
access_token
, you can send theid_token
instead. - The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below).
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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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.
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/<TENANT_ID>/signinup' \
--header 'rid: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"oAuthTokens": {
"access_token": "..."
},
}'
important
- If you don't have the
access_token
, you can send theid_token
instead. - The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below).
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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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 Android 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 need to create both a Web client and an Android for your app. The Android client will be used to interact with the native Google login APIs, the Web client will be used to request the authorization code when triggering the login flow with Google.
You also need to provide the Android client with the SHA-1 fingerprint of your keystore to prevent errors when logging in.
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 UIKit
import 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
- Single tenant setup
- Multi tenant setup
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: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"oAuthTokens": {
"access_token": "...",
"id_token": "..."
},
}'
important
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - If you have the
id_token
, you can send that along with 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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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.
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/<TENANT_ID>/signinup' \
--header 'rid: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"oAuthTokens": {
"access_token": "...",
"id_token": "..."
},
}'
important
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - If you have the
id_token
, you can send that along with 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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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.
Step 1) Fetching the OAuth / access tokens on the frontend
You can follow the instructions for the official google login library for flutter to set up your app for google login. After setting up, use the snippet below to login with google and get the access token and id token.
import 'package:google_sign_in/google_sign_in.dart';
void loginWithGoogle() async {
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
],
);
try {
var response = await _googleSignIn.signIn();
if (response == null) {
// Login was aborted
return;
}
var authentication = await response.authentication;
String? accessToken = authentication.accessToken;
String? idToken = authentication.idToken;
// TODO: See next step
} catch(e) {
// Google sign in failed
}
}
Step 2) Calling the signinup API to use the OAuth tokens
- Single tenant setup
- Multi tenant setup
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: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"oAuthTokens": {
"access_token": "...",
"id_token": "..."
},
}'
important
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - If you have the
id_token
, you can send that along with 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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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.
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/<TENANT_ID>/signinup' \
--header 'rid: thirdpartypasswordless' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"thirdPartyId": "google",
"clientType": "...",
"oAuthTokens": {
"access_token": "...",
"id_token": "..."
},
}'
important
- The
clientType
input is optional, and is required only if you have initialised more than one client in the provide on the backend (See the "Social / SSO login for both, web and mobile apps" section below). - If you have the
id_token
, you can send that along with 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.status: "SIGN_IN_UP_NOT_ALLOWED"
: This can happen due to automatic account linking. Please see our docs for account linking for more information.
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 add additional clients to the Apple.init on the backend. Each client would need to be uniquely identified and this is done using the clientType
string. For example, you can add one clientType
for web-and-android
and one for ios
.
- NodeJS
- GoLang
- Python
- Other Frameworks
Important
import { ThirdPartyProviderInput } from "supertokens-node/recipe/thirdpartypasswordless/types";
let providers: ThirdPartyProviderInput[] = [
{
config: {
thirdPartyId: "apple",
clients: [{
clientType: "web-and-android",
clientId: "...",
additionalConfig: {
"keyId": "...",
"privateKey": "...",
"teamId": "...",
}
}, {
clientType: "ios",
clientId: "...",
additionalConfig: {
"keyId": "...",
"privateKey": "...",
"teamId": "...",
}
}]
}
}
]
import (
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
)
func main() {
_ = []tpmodels.ProviderInput{{
Config: tpmodels.ProviderConfig{
ThirdPartyId: "apple",
Clients: []tpmodels.ProviderClientConfig{
{
ClientType: "web-and-android",
ClientID: "...",
AdditionalConfig: map[string]interface{}{
"keyId": "...",
"privateKey": "...",
"teamId": "...",
},
},
{
ClientType: "ios",
ClientID: "...",
AdditionalConfig: map[string]interface{}{
"keyId": "...",
"privateKey": "...",
"teamId": "...",
},
},
},
},
}}
}
from supertokens_python.recipe.thirdparty.provider import ProviderInput, ProviderConfig, ProviderClientConfig
providers = [
ProviderInput(
config=ProviderConfig(
third_party_id="apple",
clients=[
ProviderClientConfig(
client_type="web-and-android",
client_id="...",
additional_config={
"keyId": "...",
"privateKey": "...",
"teamId": "...",
},
),
ProviderClientConfig(
client_type="ios",
client_id="...",
additional_config={
"keyId": "...",
"privateKey": "...",
"teamId": "...",
},
),
],
),
),
]
For the frontend, you would need to use the right clientType
as shown below:
- Web
- Mobile
- Via NPM
- Via Script Tag
We pass in the clientType
during the init call.
import SuperTokens from 'supertokens-web-js';
SuperTokens.init({
appInfo: {
apiDomain: "<YOUR_API_DOMAIN>",
apiBasePath: "/auth",
appName: "...",
},
clientType: "web-and-android",
recipeList: [/*...*/],
});
If you are using our pre built UI SDK (supertokens-auth-react) as well, you can provide the clientType
config to it as follows:
import SuperTokens from 'supertokens-auth-react';
SuperTokens.init({
appInfo: {
apiDomain: "<YOUR_API_DOMAIN>",
websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
apiBasePath: "/auth",
appName: "...",
},
clientType: "web-and-android",
recipeList: [/*...*/],
});
We pass in the clientType
during the init call.
supertokens.init({
appInfo: {
apiDomain: "<YOUR_API_DOMAIN>",
apiBasePath: "/auth",
appName: "...",
},
clientType: "web-and-android",
recipeList: [/*...*/],
});
When making calls to the APIs from your mobile app, the request body also takes a clientType
prop as seen in the above API calls.