Skip to main content
Version: v2

Integrate with Okta OIDC

With Beyond Identity, you can configure it to add passwordless authentication to your existing authentication solution.

This guide provides information on how to configure Beyond Identity as an Identity Provider for Okta using the OpenID Connect (OIDC) identity protocol.

Prerequisites​

  • Access to a Beyond Identity tenant. If you still need to, sign up for a tenant.

  • If you do not have a Okta developer account, sign up for one.

  • Create a user in Okta that you'll use for testing. Ensure the email and username of the test user in Okta matches an account for which you can receive email. You will provision a Beyond Identity identity and passkey based on this email.

Create a new realm​

Realms are unique administrative domains within a tenant. All new tenants have a default realm called Beyond Identity Admin which should not be used to configure for delegate IDP purposes.

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 OIDC application​

  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

  1. On the External Protocol tab, under Client Configuration, set the following values:

    FieldValue
    ProtocolOIDC
    Client TypeConfidential
    Grant TypeAuthorization Code
    Redirect URIshttps://yourokta-domain.com/oauth2/v1/authorize/callback

    Example:
    https://yourokta-domain.okta.com/oauth2/v1/authorize/callback
    Token Endpoint Auth MethodClient Secret Post
    Resource ServerNone
  2. Scroll down to Token Configuration and set the following values and click Submit.

    FieldValue
    ExpirationSet to the desired expiration, for example, 604800 is one week.
    Subjectemail
    Token Signing AlgorithmRS256
  3. After the application is created, copy and save the following because you'll need these for the Identity provider configuration in Okta:

    • Token Endpoint

    • Authorization Endpoint

  4. Go the the realm's dashboard and select Edit realm.

  5. Copy and save the Realm Id and Tenant ID. Then click Cancel. You'll need these ID's to send the credential binding email.

Configure the identity provider in Okta​

  1. In Okta, select Security > Identity Providers.

  2. Click Add Identity Providers, select OpenID Connect IdP, and click Next.

  3. For Scopes, the only scope needed is openid, so you can remove the profile and email scopes.

  4. Paste the Client ID and Client Secret values from the Okta OIDC application you created in the Beyond Identity Admin console.

  5. In the Endpoints section, use the following endpoint values:

    You can find the Authorization and Token endpoints in the Okta OIDC application you created.

    NameValue
    Issuerhttps://auth-us.beyondidentity.com/v1/tenants/${tenant_id}/realms/${realm_id}/applications/${application_id}
    Authorization endpointhttps://auth-us.beyondidentity.com/v1/tenants/${tenant_id}/realms/${realm_id}/applications/${application_id}/authorize
    Token endpointhttps://auth-us.beyondidentity.com/v1/tenants/${tenant_id}/realms/${realm_id}/applications/${application_id}/token
    JWKS endpointhttps://auth-us.beyondidentity.com/v1/tenants/${tenant_id}/realms/${realm_id}/applications/${application_id}/.well-known/jwks.json
  6. In the Authentication settings section, select idpuser.externalId for IdP Username.

  7. Select Okta Username for Match against.

  8. Click the Routing Rules tab, click Add Routing Rule, and give the rule a name.

  9. From the THEN Use this identity provider drop-down, select the newly created Identity provider. The rule should match the email attribute of the test user.

  10. Click Create Rule and at the prompt click Activate.

  11. Click Finish and log out of Okta to test authentication with the newly provisioned identity.

Configure Okta to delegate authorization requests to Beyond Identity​

This section describes how to configure Okta to delegate to Beyond Identity for authentication during an OAuth2 authorization flow.
Okta will route authorization requests from a sample application you create using one of the platforms below to Beyond Identity.

Integration with Okta flow

Prerequisites​

NextAuth.js

This part of the integration guide uses NextAuth for all OAuth/OIDC flows. All code snippets are provided in the context of the NextAuth Example App.

Configuring NextAuth​

Under next-auth-example/pages/api/auth/[...nextauth].ts, add the following Okta provider:

import OktaProvider from "next-auth/providers/okta";
...
providers: [
OktaProvider({
clientId: <OKTA_CLIENT_ID>,
clientSecret: <OKTA_CLIENT_SECRET>,
issuer: <OKTA_ISSUER>
})
]
...

You'll need to fill in the <OKTA_CLIENT_ID>, <OKTA_CLIENT_SECRET>, and <OKTA_ISSUER> with the values you generated when creating your application in Okta. See the following guide mentioned in the prerequisites.


Wiring up embedded.authenticate​

Create a bi-authenticate.tsx page under /next-auth-example/pages. As long as your invoke_url is configured properly, this is the page that will be redirected to during an authorization flow. copy the following code snippet into that page.

import { useEffect, useState } from "react";
import "bootstrap/dist/css/bootstrap.css";
import { Passkey } from "@beyondidentity/bi-sdk-js";

const BIAuthenticate = () => {
const [biAuthenticateResult, setBiAuthenticateResult] = useState("");

useEffect(() => {
// -- 1
const authenticate = async () => {
const BeyondIdentityEmbeddedSdk = await import("@beyondidentity/bi-sdk-js");
let embedded = await BeyondIdentityEmbeddedSdk.Embedded.initialize();
if (embedded.isAuthenticateUrl(window.location.href)) {
// Only authenticate if the URL is a "bi-authenticate" URL
let biAuthenticateUrl = window.location.href;
// -- 2
biAuthenticate(biAuthenticateUrl).then(redirectUrl => {
// -- 4
window.location.href = redirectUrl;
}).catch(error => {
setBiAuthenticateResult(error.toString());
});
}
}
authenticate().catch(console.error);
}, []);

// -- 3
async function biAuthenticate(url: string): Promise<string> {
const BeyondIdentityEmbeddedSdk = await import("@beyondidentity/bi-sdk-js");
let embedded = await BeyondIdentityEmbeddedSdk.Embedded.initialize();

// Display passkeys so user can select one
let passkeys = await embedded.getPasskeys();
let promptText = passkeys.map((passkey, index) => {
return `${index}: ${passkey.identity.username}`;
}).join("\n");
let selectedIndex = parseInt(prompt(promptText, "index")!!);
if (selectedIndex >= 0 && selectedIndex < passkeys.length) {
let selectedId = passkeys[selectedIndex].id;
// Perform authentication using selected id
let result = await embedded.authenticate(url, selectedId);
return Promise.resolve(result.redirectUrl);
} else {
// This will fail in core as it won't match to any id
return Promise.resolve("unknown_id");
}
}

return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
}}
>
<div className="container">
<div className="row">
<div className="d-flex justify-content-center">
<div className="spinner-border" role="status">
<span className="sr-only"></span>
</div>
</div>
</div>
<div className="row">
{
biAuthenticateResult.length > 0 &&
<div className="row row-cols-1 row-cols-md-1 mt-3">
<div className="col">
<code>
{JSON.stringify(biAuthenticateResult, null, 2)}
</code>
</div>
</div>
}
</div>
</div>
</div>
);
};

export default BIAuthenticate;

What's happening here?​

  1. The useEffect is only called once on page load. In this function, we initialize the Beyond Identity SDK and use embedded.isAuthenticateUrl to check if the current page that was redirected to is in fact a valid bi-authenticate URL.
  2. If the URL is valid, we pull the URL using window.location.href and pass that directly into biAuthenticate in step 3.
  3. biAuthenticate calls embedded.authenticate with a valid bi-authenticate URL. This function performs a challenge/response against a passkey bound to your browser. Note that the callback in embedded.authenticate contains logic in order to prompt a user to select a passkey if there is more than one.
  4. Finally, the response of embedded.authenticate contains a redirectUrl. Follow this redirect URL to complete the OAuth/OIDC flow.

What does it look like?​

Upon running the next auth example app and clicking on the sign in button, you'll see the provider you just added as shown in the image below. Clicking on that provider will go through an OAuth/OIDC that will result in fetching an id token that will log you in to the example app.


image