Skip to main content
Version: v2

Add authentication

This guide describes how to add authentication to your application using the Beyond Identity Embedded SDK and a standard OAuth2/OIDC flow.

The OAuth2/OIDC calls can be set up using an OpenID Connect client library. Many frameworks and languages have their own. If you wish to find an OpenID Connect client, we recommend looking for one on the list of certified OpenID Connect clients.

In response to an OIDC request to the Beyond Identity /authorize endpoint, Beyond Identity initiates passwordless authentication by returning an authentication challenge and other information to your app. Before authenticating, your app can use the Beyond Identity SDK to enumerate available passkeys and should perform some logic to select one, such as presenting selection UI to the user. Once a passkey is selected, you can then use the SDK to complete authentication and finally perform the OAuth code for token exchange.

Overview​

With this guide you will:

  1. Create a Beyond Identity application using the Embedded SDK configuration type.
  2. Configure an OpenID Connect client library or build your own OIDC calls.
  3. Invoke and consume Beyond Identity authentication calls in your app using the Embedded SDK.

Create your Beyond Identity application​

Prerequisites​

Depending on the region you chose when you signed up, you can access the Beyond Identity admin console for your tenant at:

tip

If you are signing in from a different computer or browser, you can enter the email address you used when you signed up. Beyond Identity will send you a one time link you can use to sign in and enroll a passkey from the new browser.

Create a new realm​

So far, you have the Beyond Identity Admin Realm for your Beyond Identity tenant only. In this step, you'll create a new Realm to hold your users' identities and the configuration.

Creating a realm from the Beyond Identity Admin Console is easy.

  1. In the Admin Console, under Tenant Management, select Go to realm > Create new realm.

    Admin Console Create new realm

  2. Enter a name for your realm and click Create realm.

  3. In the confirmation dialog, switch to the new realm.

    Create new realm confirmation success

Create an application​

In this step, you'll create a new Application containing the configuration for your users.

  1. From the Admin Console, under Authentication, select Apps > Add new app.

    Admin Console Apps Add new app

  2. Give your application a name.

    Admin Console Add a new application window

On the External Protocol tab, use the following values to complete this tab.

PropertyValue
Display NameDescriptive name you choose
ProtocolOIDC

Why OIDC?

OAuth2 is primarily an authorization framework for resource access, while OIDC builds on OAuth2 to provide an identity layer for authentication, allowing client applications to obtain information about the authenticated user. Both protocols are often used together in modern applications to provide a comprehensive solution for secure authentication and authorization.

Client TypeConfidential

Why Confidential?

A "confidential" client type is ideal when your application can securely store a client secret and requires enhanced security features for token exchange and accessing user-specific resources. If your application runs in an untrusted environment or you cannot securely manage a client secret, a "public" client type might be more appropriate.

PKCES256

Why S256?

Choosing the "S256" PKCE type is strongly recommended for public clients like SPAs or mobile apps. It offers a significant security improvement over the "disabled" and "plain" options, effectively protecting against code interception attacks, which are a major concern in less secure client environments. By using "S256" PKCE, you can ensure a higher level of security for your OAuth 2.0 and OIDC flows and better protect your users' data and resources.

Redirect URIsUse a route in your app that is capable of handling the authorization code exchange.

If you are using an OpenID Connect client library, a redirect URI may be specified for you.

For example: In a Next.js application using NextAuth, your redirect URI follows the pattern:

http://localhost:3000/api/auth/callback/beyondidentity

where beyondidentity in this URI is the ID of the Auth provider as configured in the providers array in NextAuth.js and /api/auth/callback/ is based on the Next.js route file structure.

Token Endpoint Auth MethodClient Secret Basic

Why Client Secret Basic?

If your OIDC client is a confidential client and you can securely store the client secret, "client_secret_basic" is the recommended option due to its security benefits and broad support across various authorization servers. However, for public clients or environments where storing the client secret securely is challenging, you might opt for alternative authentication methods like "client_secret_post" or "none," while understanding the trade-offs in security.

Grant TypeAuthorization Code

Why Authorization Code?

The "authorization_code" grant type is suitable for confidential clients, especially when your application needs to access user-specific resources, requires Single Sign-On (SSO) support, and prioritizes security in the authentication process. It provides a secure and standardized way to obtain access to user data and resources without exposing user credentials to the client application.

All other optionsUse the default values for the remaining options

On the Authenticator Config tab, use the following values to complete this tab.

PropertyValue
Configuration TypeEmbedded SDK
Invocation TypeIn the case of a web application, this is just a URL to your web application such as 'http://localhost:3000'.
In the case of a native application (iOS, Android, Flutter, React Native), this is either an App Scheme or a Universal URL / App Link.

While app schemes are generally easier to set up, Universal URLs and App Links are recommended as they provide protection against App Scheme hijacking.

Trusted OriginsEnter your app's hostname and port, such as 'http://localhost:3000'
CHECKPOINT

Congrats! You've created and configured a Beyond Identity application. You're now ready to use the values from this applications for your OpenID Connect client.

Configure an OpenID Connect client library​

Using a library is the recommended approach because it handles authorization, token exchange and accessing user info for you.

There are many libraries available depending on your application's tech stack. If you need help finding an OpenID Connect client for your tech stack, we recommend looking for one on the list of certified OpenID Connect clients.

While there are many libraries available, they all need similar values to configure. You can find all the values you need under your External Protocol section of the application you created above.

Client ID and Client Secret will be needed for all of them, but there may be some variation in the URLs needed.

note

Remeber, if your Client Type is set to Confidential in your application's External Protocol tab then you will have a Client Secret. If the Client Type is set to Public then you will not have this value.

The Issuer and the Discovery Endpoint URL are both used by the client to identify the OpenID endpoints. The Discovery Endpoint is the Issuer + /.well-known/openid-configuration.

You can also access individual endpoints in this tab. Some libraries require copying over these URLs individually rather than using an issuer/discovery endpoint. These URLs are Authorization Endpoint, Token Endpoint and User Info Endpoint.

tip

Some libraries will require you to explicitly pass scopes or explicitly define that you are using PKCE or state. Be sure to use "openid" as a scope and configure all relevant values.

For example using a NextAuth Provider:

{
id: "beyondidentity",
name: "Beyond Identity",
type: "oauth",
wellKnown: process.env.BEYOND_IDENTITY_DISCOVERY,
authorization: { params: { scope: "openid" } },
clientId: process.env.BEYOND_IDENTITY_CLIENT_ID,
clientSecret: process.env.BEYOND_IDENTITY_CLIENT_SECRET,
idToken: true,
checks: ["pkce", "state"],
profile(profile) {
return {
id: profile.sub,
name: profile.name,
email: profile.email,
}
},
},

Consult your library for more details on which values are needed.

Craft your own authorization request​

If you are not using a library, you will need to configure your own authorization and token calls using the Authorization Endpoint and Token Endpoint found in your application's External Protocol tab.

Crafting an authorization URL is the first step in the authorization flow.

  1. In the Admin Console, under Apps, select the External Protocol tab, copy the Authorization Endpoint value and add it to the query parameters:

Authorize Url

/authorize
https://auth-$REGION.beyondidentity.com/v1/tenants/$TENANT_ID/realms/$REALM_ID/applications/$APPLICATION_ID/authorize?
response_type=code
&client_id=$CLIENT_ID
&redirect_uri=$REDIRECT_URI
&scope=openid
&state=$STATE
&code_challenge_method=256
&code_challenge=$PKCE_CODE_CHALLENGE
ParameterValue
response_typecode

This parameter specifies that the authorization server should return an authorization code to the client. The code will be used by the client to request an access token.

Grant Type must be set to Authorization Code in the console application.

client_idCopy and paste the Client ID value from your application's External Protocol tab.
redirect_uriThis parameter specifies the URL to which the authorization server can send an authorization code. If a state parameter was specified in the /authorize request, then that will be echoed back to this URL as well.

This must match one of the Redirect URIs registered in your console application.

scopeopenid

Why openid?

This scope tells the authorization server to return an

The fallback content to display on prerendering
from the /token endpoint.

stateThis parameter is a random value generated by the client. It is included in the authorization request and returned in the response. This parameter helps the client maintain state between the request and the callback to prevent cross-site request forgery (CSRF) attacks.
code_challenge_method256

Why S256?

Choosing the "S256" PKCE type is strongly recommended for public clients like SPAs or mobile apps. It offers a significant security improvement over the "disabled" and "plain" options, effectively protecting against code interception attacks, which are a major concern in less secure client environments. By using "S256" PKCE, you can ensure a higher level of security for your OAuth 2.0 and OIDC flows and better protect your users' data and resources.

This value is optional. PKCE must be enabled to S256 in the console application. If it is not enabled then you should not send the code_challenge_method or code_challenge parameters.

code_challengeThis used in conjunction with code_challenge_method ensures that the authorization code obtained by the client can only be used by the client that originally requested it.

You will need to store the hash of the code_challenge so that it can be passed to the token exchange endpoint later as a code_verifier.

This value is optional. PKCE must be enabled in the console application. If it is not enabled then you should not send the code_challenge_method or code_challenge parameters.

tip

The code_challenge is generated as defined in RFC 7636, example JavaScript snippet below:

codeVerifier = crypto.randomBytes(32).toString('base64url');
codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest()
.toString('base64url');
  1. Start authorization for Invocation Type.

Start with a GET request to your crafted authorization URL. If successful, you will receive an authenticate_url in the response. Pass that url along with a passkey id to the Embedded SDK's authenticate function. You can confirm the validity of the URL with isAuthenticateUrl.

Don't forget to initalize your SDK and present some logic to the user to select a passkey ahead of time.

const BeyondIdentityAuthUrl = `https://auth-${REGION}.beyondidentity.com/v1/tenants/${TENANT_ID}/realms/${REALM_ID}/applications/${APPLICATION_ID}/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${URI_ENCODED_REDIRECT_URI}&scope=openid&state=${STATE}&code_challenge_method=S256&code_challenge=${PKCE_CODE_CHALLENGE}`;

let response = await fetch(BeyondIdentityAuthUrl, {
method: 'GET',
headers: new Headers({
'Content-Type': 'application/json',
}),
});
const data = await response.json();

// Display UI for user to select a passkey
const passkeys = await embedded.getPasskeys();

if (await Embedded.isAuthenticateUrl(data.authenticate_url)) {
// Pass url and selected passkey ID into the Beyond Identity Embedded SDK authenticate function
// Parse query parameters from the 'redirectUrl' for a 'code' and then exchange that code for an access token in a server
const { redirectUrl } = await embedded.authenticate(
data.authenticate_url,
passkeys[0].id
);
}

Call the token endpoint for token exchange​

The authenticate call returns an object that contains a redirectURL to which your app should redirect the user to complete the OIDC flow.
Keeping with the OIDC specifications, this URL includes the code and state parameters as query parameters.

Calling the /token endpoint is the second step in the authorization flow. In this call, your app sends the code as part of an OAuth call to exchange it for an

The fallback content to display on prerendering
and
The fallback content to display on prerendering
.

  1. Click the External Protocol tab and copy the Token Endpoint.

  2. Scroll down to Client Configuration and make a note of the Token Endpoint Auth Method selected. It determines how to make the token exchange call.

    • Client Secret Post

    • Client Secret Basic

  1. Start the token exchange.

The $CLIENT_ID and $CLIENT_SECRET are sent in the Basic Authorization header.

/token
1
2
3
4
5
curl "https://auth-$(REGION).beyondidentity.com/v1/tenants/$(TENANT_ID)/realms/$(REALM_ID)/applications/$(APPLICATION_ID)/token" \
-X POST \
-u "$(CLIENT_ID):$(CLIENT_SECRET)" --basic \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=$(CODE_FROM_AUTHORIZATION_RESPONSE)&code_verifier=$(CODE_VERIFIER_IF_USED_PKCE_IN_AUTHORIZATION_REQUEST)&redirect_uri=$(REDIRECT_URI_MUST_MATCH_VALUE_USED_IN_AUTHORIZATION_REQUEST)"