bindPasskey
The bindPasskey function enables your app to generate and bind a new passkey to an identity. The identity can be one that you create via the Beyond Identity API or one that exists already in the tenant you target.
This is a reference article that describes the bindPasskey function. For a complete walk-through on creating a new passkey, see our guide Bind Passkey to an identity.
Dependencies​
The bindPasskey 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 bindPasskey, 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');
});Get a passkey binding link URL using the Beyond Identity API.
Generating a passkey binding link has several inputs and options. For details, see passkey-binding-jobs.
Use isBindPasskeyUrl to verify passkey binding link.
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
if (embedded.isBindPasskeyUrl(url)) {
// bind the passkey using `bindPasskey`
}if (EmbeddedSdk.isBindPasskeyUrl(url)) {
// bind the passkey using `bindPasskey`
}if (Embedded.shared.isBindPasskeyUrl(url)) {
// bind the passkey using `bindPasskey`
}if (await Embedded.isBindPasskeyUrl(url)) {
// bind the passkey using `bindPasskey`
}if (await Embeddedsdk.isBindPasskeyUrl(url)) {
// bind the passkey using `bindPasskey`
}
Parameters​
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
Parameter | Type | Description |
---|---|---|
url | string | Required. Passkey binding link URL. Using our public API, this can be fetched directly or sent to the email address associated with the identity. This URL enables bindPasskey to kick off the passkey creation and binding sequence for the identity that you specify. |
Parameter | Type | Description |
---|---|---|
url | String | Required. Passkey binding link URL. Using our public API, this can be fetched directly or sent to the email address associated with the identity. This URL enables bindPasskey to kick off the passkey creation and binding sequence for the identity that you specify. |
callback | (Result<BindPasskeyResponse> ) -> Unit | A callback that returns a result of type BindPasskeyResponse . |
Alternatively, you can use an overloaded version of this function to specify a dispatcher:
Parameter | Type | Description |
---|---|---|
url | String | Required. Passkey binding link URL. Using our public API, this can be fetched directly or sent to the email address associated with the identity. This URL enables bindPasskey to kick off the passkey creation and binding sequence for the identity that you specify. |
dispatcher | CoroutineDispatcher | Optional. Specifies which coroutine dispatcher to use. Default is Dispatchers.Default . |
Parameter | Type | Description |
---|---|---|
url | URL | Required. Passkey binding link URL. Using our public API, this can be fetched directly or sent to the email address associated with the identity. This URL enables bindPasskey to kick off the passkey creation and binding sequence for the identity that you specify. |
Parameter | Type | Description |
---|---|---|
url | string | Required. Passkey binding link URL. Using our public API, this can be fetched directly or sent to the email address associated with the identity. This URL enables bindPasskey to kick off the passkey creation and binding sequence for the identity that you specify. |
Parameter | Type | Description |
---|---|---|
url | String | Required. Passkey binding link URL. Using our public API, this can be fetched directly or sent to the email address associated with the identity. This URL enables bindPasskey to kick off the passkey creation and binding sequence for the identity that you specify. |
Returns​
On success, the bindPasskey function returns a Promise that resolves to a BindPasskeyResponse, which itself is an object that contains the following keys:
passkey: an object representing the newly created passkey. See example passkey.
postBindRedirect: a string containing the URL to redirect to upon successfully binding a passkey. This is the URL that you specified in the earlier call to the API to get the passkey binding link
Notes​
Call this function from client-side code, as it needs to run in either in the browser or natively on iOS/Android.
Examples​
Example: Call bindPasskey after validating passkey binding URL​
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
const url = "credential-binding-url";
if (EmbeddedSdk.isBindPasskeyUrl(url)) {
// The URL is valid for binding a passkey
EmbeddedSdk.bindPasskey(url)
.then(response => {
console.log("Success:", response);
})
.catch(err => {
console.error("Error:", err.message);
});
} else {
console.log("The URL is not a valid Bind Passkey URL");
}
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 = "credential-binding-url"
CoroutineScope(Dispatchers.Main).launch {
EmbeddedSdk.isBindPasskeyUrl(url, Dispatchers.IO).collect { isValid ->
if (isValid) {
// The URL is valid for binding a passkey
EmbeddedSdk.bindPasskey(url, Dispatchers.IO).collect { result ->
result.onSuccess {
print("Success")
}
result.onFailure {
print("Failure")
}
}
} else {
print("The URL is not a valid Bind Passkey URL")
}
}
}
let url = URL(string: "credential-binding-url")!
if Embedded.shared.isBindPasskeyUrl(url) {
// The URL is valid for binding a passkey
Embedded.shared.bindPasskey(url: url) { result in
switch result {
case .success(let bindPasskeyResponse):
// Handle successful binding
print("Successfully bound the passkey. Response: \(bindPasskeyResponse)")
case .failure(let error):
// Handle failure
print("Failed to bind the passkey. Error: \(error.localizedDescription)")
}
}
} else {
print("The URL is not a valid Bind Passkey URL.")
}
const url = "credential-binding-url";
Embedded.isBindPasskeyUrl(url)
.then(isValid => {
if (isValid) {
// The URL is valid for binding a passkey
return Embedded.bindPasskey(url);
} else {
throw new Error("The URL is not a valid Bind Passkey URL");
}
})
.then(response => {
console.log("Success:", response);
})
.catch(err => {
console.error("Error:", err.message);
});
final url = "credential-binding-url";
bool isValid = await isBindPasskeyUrl(url);
if (isValid) {
// The URL is valid for binding a passkey
try {
BindPasskeyResponse response = await bindPasskey(url);
print("Successfully bound the passkey. Response: $response");
} catch (e) {
print("Error binding the passkey: $e");
}
} else {
print("The URL is not a valid Bind Passkey URL");
}
Example: Create an identity and get passkey binding URL​
In this example, you'll first create a new identity using the API, then generate and retrieve the passkey binding URL.
To achieve this, we use several data elements:
Configuration from your BI 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. AUTHENTICATOR_CONFIG_ID The Authenticator Config ID from the Authenticator Config tab of the app's configuration page. Other passkey binding API parameters:
Property Description delivery_method Select RETURN to deliver the URL directly in the response. post_binding_redirect_uri An optional parameter that specifies a URL the user gets redirected to after a successful binding (see Returns above). The identityId returned from the first call is used for the second call.
A username passed into the function is used to create the user and establish their email name
You can find the resulting passkey binding URL in the credential_binding_link member of the response JSON returned from the second call.
Create a New Identity​
- Curl
- CSharp
- Dart
- Go
- Java
- Node
- Python
- Ruby
- Rust
Create New Identity
1 2 3 4 5 6
curl -X POST \ "${API_URL}/v1/tenants/${TENANT_ID}/realms/${REALM_ID}/identities" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ "identity": { "display_name": "${DISPLAY_NAME}", "traits": { "type": "traits_v0", "username": "${USERNAME}", "primary_email_address": "${EMAIL}" } } }"
Create New Identity
Create New Identity
Create New Identity
Create New Identity
Create New Identity
Create New Identity
Create New Identity
Create New Identity
Where the response JSON will look like:
{
"id": "e372db224c06e850",
"realm_id": "8f5bec58229e6f29",
"tenant_id": "0001f1f460b1ace6",
"display_name": "Test Identity",
"create_time": "2022-04-12T05:53:07.119Z",
"update_time": "2022-06-16T14:31:03.770Z",
"traits": {
"type": "traits_v0",
"username": "test",
"primary_email_address": "test@example.com"
}
}
Get Passkey Binding Link for Identity​
- Curl
- CSharp
- Dart
- Go
- Java
- Node
- Python
- Ruby
- Rust
Get Credential Binding Link for Identity
1 2 3 4 5 6
curl -X POST \ "${API_URL}/v1/tenants/${TENANT_ID}/realms/${REALM_ID}/identities/${IDENTITY_ID}/credential-binding-jobs" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ "job": { "delivery_method": "RETURN", "authenticator_config_id": "${AUTHENTICATOR_CONFIG_ID}", "post_binding_redirect_uri": "http://example.com" } }"
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Where the response JSON will look like:
{
"credential_binding_job": {
"id": "c4fc2d753ca22b14",
"realm_id": "cdf4862dc4d49791",
"tenant_id": "000183a77dd50fa9",
"identity_id": "87fabad6956c6d4b",
"delivery_method": "RETURN",
"state": "LINK_SENT",
"post_binding_redirect_uri": "http://example.com/callback",
"authenticator_config_id": "67bb0acf12e5c899",
"expire_time": "2022-03-21T03:42:52.905Z",
"create_time": "2022-03-14T03:42:52.905Z",
"update_time": "2022-03-15T05:55:23.823Z"
},
"credential_binding_link": "http://example.com/v1/tenants/000183a77dd50fa9/realms/cdf4862dc4d49791/identities/87fabad6956c6d4b/credential-binding-jobs/c4fc2d753ca22b14:invokeAuthenticator?token=1St9IKIIrYyQ8sOSeuk5UkbLKnBJhuD4I7nWIqt-BNANDEFS-XVuOHxB7TFdZcRm"
}
From the response above, you can see that the required binding URL is returned in the credential_binding_link member of the response JSON. This is the URL that you will pass into the bindPasskey function.
Example: Get passkey binding URL for existing identity​
To obtain a passkey binding URL for an existing identity, you will first need to retrieve the identity ID for a known user:
- Curl
- CSharp
- Dart
- Go
- Java
- Node
- Python
- Ruby
- Rust
Retrieve existing identity
1 2
curl -X GET "https://${API_URL}/v1/tenants/${TENANT_ID}/realms/${REALM_ID}/identities?filter=username%20eq%20%22john%22" \ -H "Authorization: Bearer ${API_TOKEN}"
Retrieve existing identity
Retrieve existing identity
Retrieve existing identity
Retrieve existing identity
Retrieve existing identity
Retrieve existing identity
Retrieve existing identity
Retrieve existing identity
Where the response JSON will look like:
{
"identities": [
{
"id": "e372db224c06e850",
"realm_id": "8f5bec58229e6f29",
"tenant_id": "0001f1f460b1ace6",
"display_name": "Test Identity",
"create_time": "2022-04-12T05:53:07.119Z",
"update_time": "2022-06-16T14:31:03.770Z",
"traits": {
"type": "traits_v0",
"username": "test",
"primary_email_address": "test@example.com"
}
}
],
"total_size": 1
}
You can then use the identity ID to obtain the credential binding URL:
- Curl
- CSharp
- Dart
- Go
- Java
- Node
- Python
- Ruby
- Rust
Get Credential Binding Link for Identity
1 2 3 4 5 6
curl -X POST \ "${API_URL}/v1/tenants/${TENANT_ID}/realms/${REALM_ID}/identities/${IDENTITY_ID}/credential-binding-jobs" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ "job": { "delivery_method": "RETURN", "authenticator_config_id": "${AUTHENTICATOR_CONFIG_ID}", "post_binding_redirect_uri": "http://example.com" } }"
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Get Credential Binding Link for Identity
Where the response JSON will look like:
{
"credential_binding_job": {
"id": "c4fc2d753ca22b14",
"realm_id": "cdf4862dc4d49791",
"tenant_id": "000183a77dd50fa9",
"identity_id": "87fabad6956c6d4b",
"delivery_method": "RETURN",
"state": "LINK_SENT",
"post_binding_redirect_uri": "http://example.com/callback",
"authenticator_config_id": "67bb0acf12e5c899",
"expire_time": "2022-03-21T03:42:52.905Z",
"create_time": "2022-03-14T03:42:52.905Z",
"update_time": "2022-03-15T05:55:23.823Z"
},
"credential_binding_link": "http://example.com/v1/tenants/000183a77dd50fa9/realms/cdf4862dc4d49791/identities/87fabad6956c6d4b/credential-binding-jobs/c4fc2d753ca22b14:invokeAuthenticator?token=1St9IKIIrYyQ8sOSeuk5UkbLKnBJhuD4I7nWIqt-BNANDEFS-XVuOHxB7TFdZcRm"
}
From the response above, you can see that the required binding URL is returned in the credential_binding_link member of the response JSON. This is the URL that you will pass into the bindPasskey function.
Example: Get credential binding URL via email​
The following example shows how to obtain a credential binding URL for a known identity ID via email.
- Curl
- CSharp
- Dart
- Go
- Java
- Node
- Python
- Ruby
- Rust
Send Credential Binding Link for Identity Over Email
1 2 3 4
curl -X POST "${API_URL}/v1/tenants/${TENANT_ID}/realms/${REALM_ID}/identities/${IDENTITY_ID}/credential-binding-jobs" \ -H "Authorization: Bearer ${API_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ "job": { "delivery_method": "${EMAIL}", "authenticator_config_id": "${AUTHENTICATOR_CONFIG_ID}", "post_binding_redirect_uri": "http://example.com" } }"
Send Credential Binding Link for Identity Over Email
Send Credential Binding Link for Identity Over Email
Send Credential Binding Link for Identity Over Email
Send Credential Binding Link for Identity Over Email
Send Credential Binding Link for Identity Over Email
Send Credential Binding Link for Identity Over Email
Send Credential Binding Link for Identity Over Email
Send Credential Binding Link for Identity Over Email
Where the response JSON will look like:
{
"credential_binding_job": {
"id": "c4fc2d753ca22b14",
"realm_id": "cdf4862dc4d49791",
"tenant_id": "000183a77dd50fa9",
"identity_id": "87fabad6956c6d4b",
"delivery_method": "EMAIL",
"state": "LINK_SENT",
"post_binding_redirect_uri": "http://example.com/callback",
"authenticator_config_id": "67bb0acf12e5c899",
"expire_time": "2022-03-21T03:42:52.905Z",
"create_time": "2022-03-14T03:42:52.905Z",
"update_time": "2022-03-15T05:55:23.823Z"
}
}
Notice how "credential_binding_link"
is not in the response payload since it was sent over email.
When the user clicks the link in the Beyond Identity registration email, they will be redirected to your application's Invoke URL, as configured in the Authenticator Config tab in your BI tenant, with an automatically appended '/bind' route, for example, 'http://example.com/bind', with several query string parameters appended.
Your app must have a route or page to intercept this redirect, and send it to the bindPasskey function as follows:
- JavaScript
- Kotlin
- Swift
- React Native
- Flutter
const url = "credential-binding-url";
if (EmbeddedSdk.isBindPasskeyUrl(url)) {
// The URL is valid for binding a passkey
EmbeddedSdk.bindPasskey(url)
.then(response => {
console.log("Success:", response);
})
.catch(err => {
console.error("Error:", err.message);
});
} else {
console.log("The URL is not a valid Bind Passkey URL");
}
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 = "credential-binding-url"
CoroutineScope(Dispatchers.Main).launch {
EmbeddedSdk.isBindPasskeyUrl(url, Dispatchers.IO).collect { isValid ->
if (isValid) {
// The URL is valid for binding a passkey
EmbeddedSdk.bindPasskey(url, Dispatchers.IO).collect { result ->
result.onSuccess {
print("Success")
}
result.onFailure {
print("Failure")
}
}
} else {
print("The URL is not a valid Bind Passkey URL")
}
}
}
let url = URL(string: "credential-binding-url")!
if Embedded.shared.isBindPasskeyUrl(url) {
// The URL is valid for binding a passkey
Embedded.shared.bindPasskey(url: url) { result in
switch result {
case .success(let bindPasskeyResponse):
// Handle successful binding
print("Successfully bound the passkey. Response: \(bindPasskeyResponse)")
case .failure(let error):
// Handle failure
print("Failed to bind the passkey. Error: \(error.localizedDescription)")
}
}
} else {
print("The URL is not a valid Bind Passkey URL.")
}
const url = "credential-binding-url";
Embedded.isBindPasskeyUrl(url)
.then(isValid => {
if (isValid) {
// The URL is valid for binding a passkey
return Embedded.bindPasskey(url);
} else {
throw new Error("The URL is not a valid Bind Passkey URL");
}
})
.then(response => {
console.log("Success:", response);
})
.catch(err => {
console.error("Error:", err.message);
});
final url = "credential-binding-url";
bool isValid = await isBindPasskeyUrl(url);
if (isValid) {
// The URL is valid for binding a passkey
try {
BindPasskeyResponse response = await bindPasskey(url);
print("Successfully bound the passkey. Response: $response");
} catch (e) {
print("Error binding the passkey: $e");
}
} else {
print("The URL is not a valid Bind Passkey URL");
}
For complete guidance on binding a passkey to a user, see Bind Passkey to an identity.