Skip to main content
Version: v1

Authentication with Passkey



This guide describes how to authenticate an application with a passkey using Beyond Identity within a standard OAuth2/OIDC authorization flow.

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.


1. Craft Authorization Url

First you will need to craft an authorization URL. The base url can be found in the Beyond Identity Admin Console under your application, select "EXTERNAL PROTOCOL". Copy the Authorization Endpoint and add the following additional query parameters:

Authorize Url


Check your appliction config in the admin console for your APPLICATION_CLIENT_ID.

The REDIRECT_URI is your application's App Scheme or Universal URL.


Note that the following query parameters includes PKCE as it is recommeded, but optional. If you send an authorization request with PKCE, 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.

You will need to set PKCE as a Client Configuration in your Application Config.


The STATE parameter is used to mitigiate CSRF attacks. Have your application generate a random string for the STATE value on each authentication request. You should check that this string is returned back to you to in the response.

2. Configure Authenticator Config

There are three pieces we need to check in the Authenticator Config before authentication. To check your config, navigate the Beyond Identity Admin Console and find your application. Select "AUTHENTICATOR CONFIG".

  1. In order to use the Embedded SDKs, the Configuration Type should be set to Embedded SDK.
  2. Set the Invoke URL to a URL that "points" to where your application is. In the case of a native application (iOS, Android, Flutter, React Native), this is either an App Scheme or an Universal URL / App Link. In the case of a web application, this is just a URL to your web application or a specific page of your web application.

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

  1. Set the the Invocation Type. This specifies how our authentication URL is delivered to your application. Invocation Type can be one of two values:
  • Automatic: redirect to your application using the Invoke URL with a challenge that your app will need to sign.

  • Manual: the challenge will be returned to you as part of a JSON response.

Which Invocation Type should I use?

Automatic does a lot of the heavy lifting for you. If you initiate an OAuth2.0 request and specify the "Invoke URL" correctly, we'll get the Beyond Identity authentication URL to where it needs to be, whether this is inside of a native app or a web application.

Manual gives you a lot more control, but you'll have to do a little extra work to wire this flow up. The possibilities include:

  • Completley silent OAuth 2.0 authentication using Passkeys. No redirects needed in a web app and no web view needed in a native application.
  • The flexibility to write your own intelligent routing layer using the Beyond Identity authentication URL. You may want to authenticate against passkeys in your browser on desktop, but use passkeys on your native app on mobile.

Invocation Type

3. 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}${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(

Token Exchange

Calling the token endpoint is the second step in the authorization flow and usually happens in your backend if your application's Client Type is Confidential. Make sure to a call the authorization endpoint first to retrieve an authorization code.

If your application is using the NextAuth provider (see the Javascript Authorization example using Automatic Invocation Type), you will not need to complete authentication with a token exchange.

1. Craft Token Url

The token endpoint base url can also be found in the Beyond Identity Admin Console under your application, select "EXTERNAL PROTOCOL". Copy the Token Endpoint.

Token Url

2. Token Endpoint Auth Method

Next, scroll down to "Client Configuration" and make note of your "Token Endpoint Auth Method". The "Token Endpoint Auth Method" will determin how to make the token exchange call. The token auth method can either be set to Client Secret Post or Client Secret Basic.

Token Method

3. Start Token Exchange

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

curl "https://auth-$(REGION)$(TENANT_ID)/realms/$(REALM_ID)/applications/$(APPLICATION_ID)/token" \
-u "$(CLIENT_ID):$(CLIENT_SECRET)" --basic \
-H "Content-Type: application/x-www-form-urlencoded" \