authenticate
The authenticate function enables an app using the Beyond Identity SDK to perform passkey-based authentication within a standard OpenID Connect authorization flow.
Dependencies​
The authenticate function requires the Beyond Identity SDK.
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
yarn add @beyondidentity/bi-sdk-js
or
npm install @beyondidentity/bi-sdk-js
Gradle​
To enable the retrieval of Cloudsmith hosted packages via Gradle, we need to add the Cloudsmith repository to
the root/build.gradle
file.
repositories {
maven {
url "https://packages.beyondidentity.com/public/bi-sdk-android/maven/"
}
}
After the repository is added, we can specify the Beyond Identity dependencies.
dependencies {
implementation 'com.beyondidentity.android.sdk:embedded:[version]'
}
Swift Package Manager​
From Xcode​
- From the Xcode
File
menu, selectAdd Packages
and add the following url:
https://github.com/gobeyondidentity/bi-sdk-swift
- Select a version and hit Next.
- Select a target matching the SDK you wish to use.
From Package.swift​
- With Swift Package Manager,
add the following
dependency
to yourPackage.swift
:
dependencies: [
.package(url: "https://github.com/gobeyondidentity/bi-sdk-swift.git", from: [version])
]
- Run
swift build
Cocoapods​
Add the pod to your Podfile:
pod 'BeyondIdentityEmbedded'
And then run:
pod install
After installing import with
import BeyondIdentityEmbedded
Using react-native init or an expo app.​
- react-native init
- expo
Install the SDK with yarn or npm:
yarn add @beyondidentity/bi-sdk-react-native
npm install @beyondidentity/bi-sdk-react-native
Update native requirements in your ios and android folders:
iOS​
Make sure your ios/Podfile
supports "minimum deployment target" 13.0 or later
platform :ios, '13.0'
Navigate to your ios folder and run:
cd ios && pod install
Android​
Make sure your android/build.gradle
supports minSdkVersion 26 or later
buildscript {
ext {
minSdkVersion = 26
}
}
Add the following maven url to your repositories in your android/build.gradle
allprojects {
repositories {
maven {
url "https://packages.beyondidentity.com/public/bi-sdk-android/maven/"
}
}
}
This package requires custom native code and can be used with Development builds or prebuild and cannot be used with Expo Go.
npx expo install @beyondidentity/bi-sdk-react-native
Add the SDK config plugin to the plugins array of your app.{json,config.js,config.ts}:
{
"expo": {
"plugins": [["@beyondidentity/bi-sdk-react-native"]]
}
}
The SDK requires certain minimum native versions. Set these requirments with expo-build-properties.
npx expo install expo-build-properties
{
"expo": {
"plugins": [
["@beyondidentity/bi-sdk-react-native"],
[
"expo-build-properties",
{
"android": {
"minSdkVersion": 26
},
"ios": {
"deploymentTarget": "13.0"
}
}
]
]
}
}
Finally, rebuild your app as described in Expo's Adding custom native code guide.
Pub.Dev​
Add the Beyond Identity Embedded SDK to your dependencies
dependencies:
bi_sdk_flutter: x.y.z
and run an implicit flutter pub get
.
Update Android​
Please make sure your android/build.gradle
supports minSdkVersion
26 or later.
buildscript {
ext {
minSdkVersion = 26
}
}
Update iOS​
Please make sure your project supports "minimum deployment target" 13.0 or later.
In your ios/Podfile
set:
platform :ios, '13.0'
Prerequisites​
Before making a call to authenticate, you must complete the following prerequisite calls:
Import the required types and functions from the SDK.
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
import { Embedded } from '@beyondidentity/bi-sdk-js';
import com.beyondidentity.embedded.sdk.EmbeddedSdk
import BeyondIdentityEmbedded
import { Embedded } from '@beyondidentity/bi-sdk-react-native';
import 'package:bi_sdk_flutter/embeddedsdk.dart';
Initialize the SDK.
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
// --- Initialize with required arguments
try {
const embedded = await Embedded.initialize();
console.log("Initialization successful", embedded);
} catch (error) {
console.error("Initialization failed:", error);
}
// --- Initialize with required and optional arguments
const config = {
allowedDomains: ["example.com", "another-example.com"],
logger: function (logType, message) {
console.log(`[${logType}] ${message}`);
},
};
try {
const embedded = await Embedded.initialize(config);
console.log("Initialization successful", embedded);
} catch (error) {
console.error("Initialization failed:", error);
}// --- Initialize with required arguments
EmbeddedSdk.init(
app = this,
keyguardPrompt = { allowCallback ->
// launch the keyguard service and then
// call allowCallback with the result
},
logger = { logMessage ->
Log.d("BeyondIdentityLog", logMessage)
}
)
// --- Initialize with required and optional arguments
EmbeddedSdk.init(
app = this,
keyguardPrompt = { allowCallback ->
// launch the keyguard service and then
// call allowCallback with the result
},
logger = { logMessage ->
Log.d("BeyondIdentityLog", logMessage)
},
biometricAskPrompt = getString(R.string.embedded_export_biometric_prompt_title),
allowedDomains = listOf("example.com", "another-example.com")
)// --- Initialize with required arguments
Embedded.shared.initialize(
biometricAskPrompt: "Please provide your biometric"
) { result in
switch result {
case .success():
print("Initialization successful")
case .failure(let error):
print("Initialization failed: \(error)")
}
}
// --- Initialize with required and optional arguments
Embedded.shared.initialize(
allowedDomains: ["example.com", "another-example.com"],
biometricAskPrompt: "Please provide your biometric",
logger: { (logType, message) in
print("\(logType): \(message)")
}
) { result in
switch result {
case .success():
print("Initialization successful")
case .failure(let error):
print("Initialization failed: \(error)")
}
}// --- Initialize with required arguments
try {
const response = await Embedded.initialize("Please provide your biometric");
console.log(response);
} catch (error) {
console.error("Initialization failed:", error);
}
// --- Initialize with required and optional arguments
try {
const response = await Embedded.initialize(
"Please provide your biometric", [
("example.com", "another-example.com"),
]);
console.log(response);
Embedded.logEventEmitter.addListener(
"BeyondIdentityLogger",
(message: string) => {
console.log(message);
}
);
} catch (error) {
console.error("Initialization failed:", error);
}// --- Initialize with required arguments
EmbeddedSdk.initialize('Please provide your biometric');
// --- Initialize with required and optional arguments
EmbeddedSdk.initialize(
'Please provide your biometric',
allowedDomains: ["example.com", "another-example.com"],
logger: EmbeddedSdk.enableLogger
).then(() {
print('Initialization successful');
}).catchError((error) {
print('Initialization failed: $error');
});Identify the passkey you wish to authenticate with and obtain its passkey ID.
How you achieve this depends upon your app, but you can obtain a list of passkeys available on the device via the getPasskeys function. This returns an array of passkeys that you can use, for example, to prompt the user interactively to select one. The id property of the selected Passkey is the passkey id this function expects
Use isAuthenticateUrl to verify the
url
parameter you intend to send to the function- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
if (embedded.isAuthenticateUrl(url)) {
// authenticate against a passkey bound to the device
}if (EmbeddedSdk.isAuthenticateUrl(url)) {
// authenticate against a passkey bound to the device
}if (Embedded.shared.isAuthenticateUrl(url)) {
// authenticate against a passkey bound to the device
}if (await Embedded.isAuthenticateUrl(url)) {
// authenticate against a passkey bound to the device
}if (await Embeddedsdk.isAuthenticateUrl(url)) {
// authenticate against a passkey bound to the device
}
Parameters​
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
Parameter | Type | Description |
---|---|---|
url | string | Required. A Beyond Identity authentication URL is generated by the Beyond Identity API's /authorize endpoint in response to a standard OpenID Connect request from your app (see example below). The generated URL is unique for each authentication request. It contains an encoded JWT token containing the challenge for the passkey to sign. |
passkeyId | string | Required. The ID of the passkey that you wish to use for the authentication. This should match the id property of a Passkey available on the device. |
Parameter | Type | Description |
---|---|---|
url | String | Required. A Beyond Identity authentication URL is generated by the Beyond Identity API's /authorize endpoint in response to a standard OpenID Connect request from your app (see example below). The generated URL is unique for each authentication request. It contains an encoded JWT token containing the challenge for the passkey to sign. |
passkeyId | String | Required. The ID of the passkey that you wish to use for the authentication. This should match the id property of a Passkey available on the device. |
Parameter | Type | Description |
---|---|---|
url | URL | Required. A Beyond Identity authentication URL is generated by the Beyond Identity API's /authorize endpoint in response to a standard OpenID Connect request from your app (see example below). The generated URL is unique for each authentication request. It contains an encoded JWT token containing the challenge for the passkey to sign. |
passkeyId | Passkey.Id | Required. The ID of the passkey that you wish to use for the authentication. This should match the id property of a Passkey available on the device. |
Parameter | Type | Description |
---|---|---|
url | string | Required. A Beyond Identity authentication URL is generated by the Beyond Identity API's /authorize endpoint in response to a standard OpenID Connect request from your app (see example below). The generated URL is unique for each authentication request. It contains an encoded JWT token containing the challenge for the passkey to sign. |
passkeyId | string | Required. The ID of the passkey that you wish to use for the authentication. This should match the id property of a Passkey available on the device. |
Parameter | Type | Description |
---|---|---|
url | String | Required. A Beyond Identity authentication URL is generated by the Beyond Identity API's /authorize endpoint in response to a standard OpenID Connect request from your app (see example below). The generated URL is unique for each authentication request. It contains an encoded JWT token containing the challenge for the passkey to sign. |
passkeyId | String | Required. The ID of the passkey that you wish to use for the authentication. This should match the id property of a Passkey available on the device. |
Returns​
On success, the authenticate function returns the following response:
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
{
redirectUrl: string;
message?: string;
}
data class AuthenticateResponse(
val redirectUrl: String?,
val message: String?,
)
struct AuthenticateResponse: Codable, Equatable {
let redirectUrl: URL
let message: String?
}
interface AuthenticateResponse {
redirectUrl: string;
message?: string;
}
class AuthenticateResponse(
String redirectUrl,
String message,
)
redirectURL: string containing the complete URL to which your app should redirect the user to complete the OIDC flow.
Keeping with the OIDC specifications, this includes the code and state parameters as query parameters to the redirect_url specified in the original OIDC request to the
/authorize
endpoint for the authentication URL.message: string containing a message your app may optionally consume or display.
Notes​
Using the authenticate function requires your app to generate a standard OpenID Connect (OIDC) request to Beyond Identity's API and consume the resulting codes and tokens.
For step-by-step instructions to on how to configure authentication using the embedded SDK, see this guide.
Examples​
Example: Call authenticate with selected ID after prompting the user with a list of passkeys​
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
const url = "authenticate-url";
try {
// Fetch all passkeys for this browser
const passkeys = await embedded.getPasskeys();
// Check if there are any passkeys available
if (passkeys.length > 0) {
// TODO: Instead of automatically selecting the first passkey,
// present a UI to the user to let them select the desired passkey.
// For the purpose of this example, we're using the first passkey.
const passkeyId = passkeys[0].passkeyId;
if (embedded.isAuthenticateUrl(url)) {
// The URL is valid for authenticating against a passkey
const response = await embedded.authenticate(url, passkeyId);
console.log(`Successfully authenticated against passkey bound to this browser. Response: ${JSON.stringify(response)}`);
} else {
console.log("The URL is not a valid Authenticate Passkey URL");
}
} else {
console.log("No passkeys available for this browser");
}
} catch (error) {
console.error(`Error: ${error}`);
}
import com.beyondidentity.embedded.sdk.EmbeddedSdk
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.collect
val url = "authenticate-url"
CoroutineScope(Dispatchers.Main).launch {
// Fetch all passkeys for this device
EmbeddedSdk.getPasskeys(Dispatchers.IO).collect { result ->
result.onSuccess { passkeys ->
// Check if there are any passkeys available
if (passkeys.isNotEmpty()) {
// TODO: Instead of automatically selecting the first passkey,
// present a UI to the user to let them select the desired passkey.
// For the purpose of this example, we're using the first passkey.
val passkeyId = passkeys.first().passkeyId
EmbeddedSdk.isAuthenticateUrl(url, Dispatchers.IO).collect { isValid ->
if (isValid) {
// The URL is valid for authenticating against a passkey
EmbeddedSdk.authenticate(url, passkeyId, Dispatchers.IO).collect { authResult ->
authResult.onSuccess { response ->
print("Successfully authenticated against passkey bound to this device. Response: $response")
}
authResult.onFailure { e ->
print("Error authenticating against a passkey: $e")
}
}
} else {
print("The URL is not a valid Authenticate Passkey URL")
}
}
} else {
print("No passkeys available for this device")
}
}
result.onFailure { e ->
print("Error fetching passkeys: $e")
}
}
}
let url = URL(string: "authenticate-url")!
// Fetch all passkeys for this device
Embedded.shared.getPasskeys { result in
switch result {
case .success(let passkeys):
// Check if there are any passkeys available
if !passkeys.isEmpty {
// TODO: Instead of automatically selecting the first passkey,
// present a UI to the user to let them select the desired passkey.
// For the purpose of this example, we're using the first passkey.
let passkeyId = passkeys.first!.id
if Embedded.shared.isAuthenticateUrl(url) {
// The URL is valid for authenticating against a passkey
Embedded.shared.authenticate(url: url, id: passkeyId) { authResult in
switch authResult {
case .success(let response):
print("Successfully authenticated against passkey bound to this device. Response: \(response)")
case .failure(let error):
print("Error authenticating against a passkey: \(error.localizedDescription)")
}
}
} else {
print("The URL is not a valid Authenticate Passkey URL")
}
} else {
print("No passkeys available for this device")
}
case .failure(let error):
print("Error fetching passkeys: \(error.localizedDescription)")
}
}
const url = "authenticate-url";
try {
// Fetch all passkeys for this device
const passkeys = await Embedded.getPasskeys();
// Check if there are any passkeys available
if (passkeys.length > 0) {
// TODO: Instead of automatically selecting the first passkey,
// present a UI to the user to let them select the desired passkey.
// For the purpose of this example, we're using the first passkey.
const passkeyId = passkeys[0].passkeyId;
const isValid = await Embedded.isAuthenticateUrl(url);
if (isValid) {
// The URL is valid for authenticating against a passkey
try {
const response = await Embedded.authenticate(url, passkeyId);
console.log("Successfully authenticated against passkey bound to this device. Response:", response);
} catch (e) {
console.error("Error authenticating against a passkey:", e);
}
} else {
console.log("The URL is not a valid Authenticate Passkey URL");
}
} else {
console.log("No passkeys available for this device");
}
} catch (error) {
console.error("Error fetching passkeys:", error);
}
final url = "authenticate-url";
// Fetch all passkeys for this device
List<Passkey> passkeys = await EmbeddedSdk.getPasskeys();
// Check if there are any passkeys available
if (passkeys.isNotEmpty) {
// TODO: Instead of automatically selecting the first passkey,
// present a UI to the user to let them select the desired passkey.
// For the purpose of this example, we're using the first passkey.
String passkeyId = passkeys.first.passkeyId;
bool isValid = await EmbeddedSdk.isAuthenticateUrl(url);
if (isValid) {
// The URL is valid for authenticating against a passkey
try {
AuthenticateResponse response = await EmbeddedSdk.authenticate(url, passkeyId);
print("Successfully authenticated against passkey bound to this device. Response: $response");
} catch (e) {
print("Error authenticating against a passkey: $e");
}
} else {
print("The URL is not a valid Authenticate Passkey URL");
}
} else {
print("No passkeys available for this device");
}
Example: Retrieve Beyond Identity authentication url via OIDC call​
The app sends an OIDC call to the Beyond Identity API's /authorize
endpoint:
- Curl
- CSharp
- Dart
- Go
- Java
- Node
- Python
- Ruby
- Rust
Call /authorize Endpoint to Initiate OIDC Call
1
curl -X GET "https://auth-us.beyondidentity.com/v1/tenants/${TENANT_ID}/realms/${REALM_ID}/applications/${APPLICATION_ID}/authorize?client_id=${CLIENT_ID}&scope=openid&response_type=code&redirect_uri=${REDIRECT_URI}&state=8LIY29kN8Oz7zrAhb8xb0yvem-gvnRy1HTn03MAuL_E"
Call /authorize Endpoint to Initiate OIDC Call
Call /authorize Endpoint to Initiate OIDC Call
Call /authorize Endpoint to Initiate OIDC Call
Call /authorize Endpoint to Initiate OIDC Call
Call /authorize Endpoint to Initiate OIDC Call
Call /authorize Endpoint to Initiate OIDC Call
Call /authorize Endpoint to Initiate OIDC Call
Call /authorize Endpoint to Initiate OIDC Call
where the following elements match the corresponding properties of the app as configured in your Beyond Identity tenant:
Property | Description |
---|---|
TENANT_ID | The Tenant ID of the tenant in which the app is configured. |
REALM_ID | The Realm ID of the realm in which the app is configured. |
APPLICATION_ID | The Application ID from the header of the app's configuration page. |
CLIENT_ID | The Client ID from the External Protocol tab of the app's configuration page. |
REDIRECT_URI | Matches one of the Redirect URIs configured on the External Protocol tab of the app's configuration page, URL encoded. |
When the Invocation Type configured on the Authenticator Config tab of the app's configuration page is set to Manual, it returns a JSON object:
{ "authenticate_url": "http://localhost:8083/bi-authenticate?request={BI_JWT}" }
where BI_JWT is a base64url encoded JWT token containing the challenge and other data to kick off the passkey authentication.
When the Invocation Type on the app is set to Automatic, it returns an HTTP 302 to the authentication URL:
http/1.1 302 Found
...
location: http://localhost:8083/bi-authenticate?request={BI_JWT}
where BI_JWT is a base64url encoded JWT token containing the challenge and other data to kick off the passkey authentication.