Social Login (OAuth) with Backend SDKs
This guide is meant for developers that are NOT using Descope on the frontend to design login screens and authentication methods.
If you'd like to use Descope Flows, Quick Start should be your starting point. If you'd like to use our Client SDKs, refer to our Client SDK docs.
To get started with authentication using Social Login (OAuth), refer to our Social Login Documentation. Continue reading to learn how to integrate Social Login into your application using our Backend SDKs.
Building an MCP Server?
If you are securing a Model Context Protocol (MCP) server, use the Descope Python MCP SDK (descope-mcp) instead of the standard backend SDK. It handles OAuth 2.1 token validation, scope enforcement, and connection token retrieval specifically for MCP servers. See the Agentic Identity Hub for full setup instructions.
Backend SDK
Install SDK
npm i --save @descope/node-sdkpip3 install descopego get github.com/descope/go-sdk// Include the following in your `pom.xml` (Maven)
<dependency>
<artifactId>java-sdk</artifactId>
<groupId>com.descope</groupId>
<version>sdk-version</version> // Check https://github.com/descope/descope-java/releases for the latest versions
</dependency>gem install descopecomposer require descope/descope-phpdotnet add package descopeImport and initialize SDK
import DescopeClient from '@descope/node-sdk';
try{
// baseUrl="<URL>" // When initializing the Descope client, you can also configure the baseUrl ex: https://auth.company.com - this is useful when you utilize a custom domain within your Descope project.
const descopeClient = DescopeClient({ projectId: '__ProjectID__' });
} catch (error) {
// handle the error
console.log("failed to initialize: " + error)
}from descope import (
REFRESH_SESSION_TOKEN_NAME,
SESSION_TOKEN_NAME,
AuthException,
DeliveryMethod,
DescopeClient,
AssociatedTenant,
RoleMapping,
AttributeMapping,
LoginOptions
)
try:
# You can configure the baseURL by setting the env variable Ex: export DESCOPE_BASE_URI="https://auth.company.com - this is useful when you utilize custom domain within your Descope project."
descope_client = DescopeClient(project_id='__ProjectID__')
except Exception as error:
# handle the error
print ("failed to initialize. Error:")
print (error)import "github.com/descope/go-sdk/descope"
import "github.com/descope/go-sdk/descope/client"
// Utilizing the context package allows for the transmission of context capabilities like cancellation
// signals during the function call. In cases where context is absent, the context.Background()
// function serves as a viable alternative.
// Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
import (
"context"
)
// DescopeBaseURL // within the client.Config, you can also configure the baseUrl ex: https://auth.company.com - this is useful when you utilize a custom domain within your Descope project.
descopeClient, err := client.NewWithConfig(&client.Config{ProjectID:"__ProjectID__"})
if err != nil {
// handle the error
log.Println("failed to initialize: " + err.Error())
}import com.descope.client.Config;
import com.descope.client.DescopeClient;
var descopeClient = new DescopeClient(Config.builder().projectId("__ProjectID__").build());require 'descope'
@project_id = ENV['__ProjectID__']
@client = Descope::Client.new({ project_id: @project_id})require 'vendor/autoload.php';
use Descope\SDK\DescopeSDK;
$descopeSDK = new DescopeSDK([
'projectId' => $_ENV['__ProjectID__'],
]);// appsettings.json
{
"Descope": {
"ProjectId": "__ProjectID__",
"ManagementKey": "DESCOPE_MANAGEMENT_KEY"
}
}
// Program.cs
using Descope;
using Microsoft.Extensions.Configuration;
// ... In your setup code
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var descopeProjectId = config["Descope:ProjectId"];
var descopeManagementKey = config["Descope:ManagementKey"];
var descopeConfig = new DescopeConfig(projectId: descopeProjectId);
var descopeClient = new DescopeClient(descopeConfig)
{
ManagementKey = descopeManagementKey,
};Start OAuth
To initiate the OAuth process, call the OAuth initiation function after the user clicks the social login button. This function returns a pre-formatted URL that the client can use to redirect the user and begin the login flow with the selected Identity Provider (e.g., Google, Facebook, Microsoft).
// Args:
// provider: social identity provider for authenticating the user. Supported values include "facebook", "github", "google", "microsoft", "gitlab" and "apple". The current list can be found at https://github.com/descope/descope-js/blob/main/packages/sdks/core-js-sdk/src/sdk/oauth/types.ts in the OAuthProviders array.
const provider = "facebook"
// redirect_url: URL to return to after successful authentication with the social identity provider. You need to implement this page to access the token and finish oauth process (token exchange). The token arrives as a query parameter named 'code'.
const redirect_url = "https://auth.company.com/token_exchange"
// login_hint: Optional hint (e.g., user email) to pre-fill the identity provider's login form.
const login_hint = "user@example.com"
// loginOptions (LoginOptions): this allows you to configure behavior during the authentication process.
const loginOptions = {
"stepup": false,
"mfa": false,
"customClaims": {"claim": "Value1"},
"templateOptions": {"option": "Value1"}
}
// refreshToken (optional): the user's current refresh token in the event of stepup/mfa
const resp = await descopeClient.oauth.start[provider](redirect_url, login_hint, loginOptions);
if (!resp.ok) {
console.log("Failed to start oauth")
console.log("Status Code: " + resp.code)
console.log("Error Code: " + resp.error.errorCode)
console.log("Error Description: " + resp.error.errorDescription)
console.log("Error Message: " + resp.error.errorMessage)
}
else {
const provider_url = resp.data.url
console.log("Successfully started oauth. URL: " + provider_url)
}# Args:
# provider: social identity provider for authenticating the user. Supported values include "facebook", "github", "google", "microsoft", "gitlab" and "apple". The current list can be found at https://github.com/descope/python-sdk/blob/main/descope/common.py in the OAuthProvider array.
provider = "facebook"
# redirect_url: URL to return to after successful authentication with the social identity provider. You need to implement this page to access the token and finish oauth process (token exchange). The token arrives as a query parameter named 'code'.
redirect_url = "https://auth.company.com/token_exchange"
# login_options (LoginOptions): this allows you to configure behavior during the authentication process.
login_options = {
"stepup": false,
"mfa": false,
"custom_claims": {"claim": "Value1"},
"template_options": {"option": "Value1"}
}
# refresh_token (optional): the user's current refresh token in the event of stepup/mfa
try:
resp = descope_client.oauth.start(provider=provider, return_url=redirect_url, login_options=login_options)
print ("Successfully started Oauth flow")
print (resp)
except AuthException as error:
print ("Failed to start Oauth flow")
print ("Status Code: " + str(error.status_code))
print ("Error: " + str(error.error_message))// ctx: context.Context - Application context for the transmission of context capabilities like
// cancellation signals during the function call. In cases where context is absent, the context.Background()
// function serves as a viable alternative.
// Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
ctx := context.Background()
// provider: This is the OAuthProvider such as facebook, google, etc
provider := descope.OAuthFacebook
// returnURL: url for redirecting the user after authentication with social oauth provider. This value will override the value in the console settings. You need to implement this page to access the token and finish oauth process (token exchange). The token arrives as a query parameter named 'code'.
returnURL := "https://auth.company.com/token_exchange"
// loginHint: Optional hint (e.g., user email) to pre-fill the identity provider's login form.
loginHint := "user@example.com";
// r: HttpRequest for the update call. This request should contain refresh token for the authenticated user.
// loginOptions: this allows you to configure behavior during the authentication process.
loginOptions := &descope.LoginOptions{
Stepup: true,
MFA: true,
CustomClaims: map[string]any{}{"test": "testClaim"},
TemplateOptions: map[string]any{"option": "Value1"}
}
// w: ResponseWriter to update with correct redirect url. You can return this to your client for redirect.
// Use either the SignUpOrIn, SignUp, or SignIn function
res, err := descopeClient.Auth.OAuth.SignUpOrIn(ctx, provider, returnURL, loginHint, r, loginOptions, w)
if (err != nil){
fmt.Println("Failed to initialize oauth flow: ", err)
} else {
fmt.Println("Successfully started Oauth flow: ", res)
}// Choose an oauth provider out of the supported providers
// If configured globally, the return URL is optional. If provided however, it will be used
// instead of any global configuration.
// Redirect the user to the returned URL to start the OAuth redirect chain
OAuthService oas = descopeClient.getAuthenticationServices().getOAuthService();
try {
String returnUrl = "https://my-app.com/handle-oauth";
oas.start("google", returnUrl, loginOptions);
} catch (DescopeException de) {
// Handle the error
}descope_client.oauth_start(
provider: 'google', # Choose an oauth provider out of the supported providers
return_url: 'https://my-app.com/handle-oauth', # Can be configured in the console instead of here
)// Args:
// provider (string): The OAuth provider to sign up with (e.g., "google").
var provider = "google";
// redirectUrl (string?): Optional redirect URL; if null, the default redirect URL in Descope console will be used.
string? redirectUrl = "https://auth.company.com/token_exchange";
// loginOpts (LoginOptions?): Step-up / MFA / custom claims.
LoginOptions? loginOpts = new LoginOptions
{
StepupRefreshJwt = null, // or an existing refresh JWT for step-up
MfaRefreshJwt = null, // or an existing refresh JWT for MFA
CustomClaims = new Dictionary<string, object>
{
["attribute1"] = "attribute-value"
}
};
// Sign up a new user
try
{
var url = await descopeClient.Auth.OAuth.SignUp(provider: provider, redirectUrl: redirectUrl, loginOptions: loginOpts);
}
catch (DescopeException ex)
{
// Handle the error
}
// Sign in an existing user
try
{
var url = await descopeClient.Auth.OAuth.SignIn(provider: provider, redirectUrl: redirectUrl, loginOptions: loginOpts);
}
catch (DescopeException ex)
{
// Handle the error
}
// Sign up or sign in depending on whether the user exists
try
{
var url = await descopeClient.Auth.OAuth.SignUpOrIn(provider: provider, redirectUrl: redirectUrl, loginOptions: loginOpts);
}
catch (DescopeException ex)
{
// Handle the error
}Finish OAuth (Exchange Token)
After the user authenticates with the OAuth provider, they will be redirected to the redirect_url you specified.
However, to complete the login process with Descope, you'll need to extract the code from the URL and perform the token exchange which will complete the OAuth flow:
// Args:
// code: code extracted from the url after user is redirected to redirect_url. The code is in the url as a query parameter "code" of the page.
const code = "xxxxx"
const response = await descopeClient.oauth.exchange(code);
if (!resp.ok) {
console.log("Failed to finish oauth")
console.log("Status Code: " + resp.code)
console.log("Error Code: " + resp.error.errorCode)
console.log("Error Description: " + resp.error.errorDescription)
console.log("Error Message: " + resp.error.errorMessage)
}
else {
console.log("Successfully finished oauth.")
console.log(resp)
}# Args:
# code: code extracted from the url after user is redirected to redirect_url. The code is in the url as a query parameter "code" of the page.
code = "xxxxx"
try:
resp = descope_client.oauth.exchange_token(code=code)
print ("Successfully Finished Oauth flow")
print (resp)
except AuthException as error:
print ("Failed to finish Oauth flow")
print ("Status Code: " + str(error.status_code))
print ("Error: " + str(error.error_message))// Args:
// ctx: context.Context - Application context for the transmission of context capabilities like
// cancellation signals during the function call. In cases where context is absent, the context.Background()
// function serves as a viable alternative.
// Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
ctx := context.Background()
// code (string): code should be extracted from the redirect URL of OAuth authentication from the query parameter `code`.
code := "xxxxxx"
// w: ResponseWriter to update with correct session details. You can return this to your client for setting the cookies which are used for session validation
authInfo, err := descopeClient.Auth.OAuth.ExchangeToken(ctx, code, w)
if (err != nil){
fmt.Println("Failed to finish Oauth flow: ", err)
} else {
fmt.Println("Successfully Finished Oauth flow: ", authInfo)
}OAuthService oas = descopeClient.getAuthenticationServices().getOAuthService();
try {
AuthenticationInfo info = oas.exchangeToken(code);
} catch (DescopeException de) {
// Handle the error
}jwt_response = descope_client.oauth_exchange_token(code)
session_token = jwt_response[Descope::Mixins::Common::SESSION_TOKEN_NAME].fetch('jwt')
refresh_token = jwt_response[Descope::Mixins::Common::REFRESH_SESSION_TOKEN_NAME].fetch('jwt')// Args:
// code (string): code extracted from the url after user is redirected to redirect_url. The code is in the url as a query parameter "code" of the page.
var code = "authorization-code";
try
{
var authInfo = await descopeClient.Auth.OAuth.Exchange(code: code);
}
catch (DescopeException ex)
{
// Handle the error
}Session Validation
The final step of completing the authentication with Descope is to validate the user session. Descope provides rich session management capabilities, including configurable session timeouts and logout functions. You can find the details and sample code for backend session validation here.
Checkpoint
Your application is now integrated with Descope. Please test with sign-up or sign-in use case.