Skip to main content
Which UI do you use?
Custom UI
Pre built UI

Custom providers

If SuperTokens doesn't support a provider out of the box, you can add your own custom provider as shown below.

note

If you think that this provider should be supported by SuperTokens by default, make sure to let us know here.

Frontend#

import React from "react";
import SuperTokens from "supertokens-auth-react";
import ThirdParty from "supertokens-auth-react/recipe/thirdparty";
SuperTokens.init({
appInfo: {
apiDomain: "...",
appName: "...",
websiteDomain: "..."
},
recipeList: [
ThirdParty.init({
signInAndUpFeature: {
providers: [
{
id: "custom",
name: "X", // Will display "Continue with X"

// optional
// you do not need to add a click handler to this as
// we add it for you automatically.
buttonComponent: (props: {name: string}) => <div style={{
cursor: "pointer",
border: "1",
paddingTop: "5px",
paddingBottom: "5px",
borderRadius: "5px",
borderStyle: "solid"
}}>{"Login with " + props.name}</div>
}
],
// ...
},
// ...
}),
// ...
]
});

Backend#

Via OAuth endpoints#

There are a couple of ways you can define a custom provider. The simplest method is to provide the config for the AuthorizationEndpoint, TokenEndpoint, and the mapping for how the user's ID and email from the provider's profile information endpoint. This can be seen below:

import SuperTokens from "supertokens-node";
import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";

SuperTokens.init({
appInfo: {
appName: "...",
apiDomain: "...",
websiteDomain: "...",
},
recipeList: [
ThirdPartyEmailPassword.init({
providers: [{
config: {
thirdPartyId: "custom",
name: "Custom provider",
clients: [{
clientId: "...",
clientSecret: "...",
scope: ["profile", "email"]
}],
authorizationEndpoint: "https://example.com/oauth/authorize",
authorizationEndpointQueryParams: {
"someKey1": "value1",
"someKey2": null
},
tokenEndpoint: "https://example.com/oauth/token",
tokenEndpointBodyParams: {
"someKey1": "value1",
},
userInfoEndpoint: "https://example.com/oauth/userinfo",
userInfoMap: {
fromUserInfoAPI: {
userId: "id",
email: "email",
emailVerified: "email_verified",
}
}
}
}]
})
]
})
  • The thirdPartyId is a unique ID for this provider which helps SuperTokens identify the provider. For example, the thirdPartyId for the built in Google provider is "google".

  • The name field is sent to the frontend and can be used to render the login button on the frontend UI. For example, if you set the name to "XYZ", the pre built UI on the frontend will display the text "Login using XYZ" on the button for this provider.

  • The clients array represents the client credentials / settings for each of your frontend clients. Most of the time, one client item is enough, but if the provider requires to use different client ID / secret for web vs mobile apps, you would need to add two items to this array - one for web, and one for mobile. In this case, you would also need to add the clientType: string config for each of the items in the clients array.

  • AuthorizationEndpoint corresponds to the URL to which the user should be redirected to for the login. For example for Google, this is "https://accounts.google.com/o/oauth2/v2/auth".

    • AuthorizationEndpointQueryParams is an optional config, but it can be used to modify the query params added to the AuthorizationEndpoint. You can use this config to add new keys, or to modify or remove (by setting to null) query params added by SuperTokens.
  • TokenEndpoint corresponds to the API that is used to exchange Authorization Code for the user's Access Token or the ID Token. For example for Google, the value of this is "https://oauth2.googleapis.com/token".

    • TokenEndpointBodyParams is an optional config, but it can be used to modify the request body sent to the TokenEndpoint. You can use this config to add new keys, or to modify or remove (by setting to null) body params added by SuperTokens.
  • UserInfoEndpoint corresponds to the API that provides user information using the AccessToken. For Google, the value of this is "https://www.googleapis.com/oauth2/v1/userinfo". Once this endpoint is called, SuperTokens fetches user info (like their userID and email ID) from the JSON response based on the config for UserInfoMap.FromUserInfoAPI map. For example, the value of the map for Google is:

    {
    userId: "id",
    email: "email",
    emailVerified: "email_verified"
    }

    This means that when SuperTokens gets back the JSON from the /userinfo endpoint, it will read the jsonResponse.id field to get the user's Google ID, the jsonResponse.email field to get back the user's email and the jsonResponse.email_verified field to know if the user's email is verified or not.

    If you want to fetch a value from a nested JSON object, you can specify something like userId: "user.id", in which case the provider's user ID will be fetched using jsonResponse.user.id.

Via Open ID connect (OIDC) endpoints#

If the provider is Open ID Connect (OIDC) compatible, you can provide url for the OIDCDiscoverEndpoint config. The backend SDK will automatically discover authorization endpoint, token endpoint and the user info endpoint by querying the <OIDCDiscoverEndpoint>/.well-known/openid-configuration.

Below is an example of how to set the OIDC discovery endpoint:

import SuperTokens from "supertokens-node";
import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";

SuperTokens.init({
appInfo: {
appName: "...",
apiDomain: "...",
websiteDomain: "...",
},
recipeList: [
ThirdPartyEmailPassword.init({
providers: [{
config: {
thirdPartyId: "custom",
name: "Custom provider",
clients: [{
clientId: "...",
clientSecret: "...",
scope: ["profile", "email"]
}],
oidcDiscoveryEndpoint: "https://example.com/.well-known/openid-configuration",
authorizationEndpointQueryParams: {
"someKey1": "value1",
"someKey2": null
},
userInfoMap: {
fromIdTokenPayload: {
userId: "id",
email: "email",
emailVerified: "email_verified",
}
}
}
}]
})
]
})
  • The config values are similar to the ones in the "Via OAuth endpoints" method. Please read that section to understand the thirdPartyId, name, clients config.
  • Unlike the "Via OAuth endpoints", we extract the user's info from the ID token payload using the config specified by you in the UserInfoMap.FromIdTokenPayload map.
  • You can also add the UserInfoMap.FromUserInfoAPI map as done in the "Via OAuth endpoints" section. SuperTokens will auto merge the user information.

Handling non standard providers.#

Sometimes, one of the steps in the providers interaction may not be as per a standard. Therefore just providing the config like shown above may not work. To handle this case, we allow you to override any the steps that happen during the OAuth exchange.

For example, the API call made to get the user's profile info makes a GET call to the UserInfoEndpoint with the user's access token. If your provider requires a different method or requires multiple calls to different endpoints to get the profile info, then you can override the default implementation as shown below:

import SuperTokens from "supertokens-node";
import ThirdPartyEmailPassword from "supertokens-node/recipe/thirdpartyemailpassword";

SuperTokens.init({
appInfo: {
appName: "...",
apiDomain: "...",
websiteDomain: "...",
},
recipeList: [
ThirdPartyEmailPassword.init({
providers: [{
config: {
thirdPartyId: "custom",
name: "Custom provider",
clients: [{
clientId: "...",
clientSecret: "...",
scope: ["profile", "email"]
}],
authorizationEndpoint: "https://example.com/oauth/authorize",
authorizationEndpointQueryParams: {
"response_type": "token", // Changing an existing parameter
"response_mode": "form", // Adding a new parameter
"scope": null, // Removing a parameter
},
tokenEndpoint: "https://example.com/oauth/token"
},
override: (originalImplementation) => {
return {
...originalImplementation,
getUserInfo: async function (input) {
// Call provider's APIs to get profile info
// ...
return {
thirdPartyUserId: "...",
email: {
id: "...",
isVerified: true
},
rawUserInfoFromProvider: {
fromUserInfoAPI: {
"first_name": "...",
"last_name": "..."
},
}
}
}
}
}
}]
})
]
})

The original implementation has 4 functions which can be overidden:

  1. GetConfigForClientType

    Selects the client config from the list of clients provided and returns the complete provider config. This is a good place to override config dynamically. For example, if login_hint is provided in the request, it can be added to the AuthorizationEndpointQueryParams by overriding this function.

  2. GetAuthorisationRedirectURL

    This function returns the full URL (along with query params) to which the user needs to be navigated to in order to login.

  3. ExchangeAuthCodeForOAuthTokens

    This function is responsible for exchanging one time use Authorization Code with the user's tokens, such as Access Token, ID Token, etc.

  4. GetUserInfo

    This function is responsible for fetching the user information such as UserId, Email and EmailVerified using the tokens returned from the previous function.

See also#