Dart SDK
passkeybase
The passkeybase package provides a Dart client for the PasskeyBase Management API. Manage users, credentials, clients, roles, tenant settings, and enrollment tokens from your Dart or Flutter backend.
Installation
Add the package from pub.dev:
dart pub add passkeybaseRequirements: Dart SDK >= 3.0.0. Dependencies:http (HTTP transport) andcrypto (enrollment token signing).
Quick Start
Initialize the client with your M2M credentials and tenant domain, then make your first API call. The SDK handles OAuth2 client_credentialstoken acquisition and refresh automatically.
import 'package:passkeybase/passkeybase.dart';
final client = PasskeyBaseClient(
domain: 'myapp.auth.ing',
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
);
// List all users
final users = await client.users.list(page: 1, perPage: 20);
for (final user in users.data) {
print('${user.id}: ${user.name}');
}
// Always close the client when done
client.close();Configuration
import 'package:passkeybase/passkeybase.dart';
import 'package:http/http.dart' as http;
final client = PasskeyBaseClient(
domain: 'myapp.auth.ing', // Required. Your tenant domain.
clientId: 'YOUR_CLIENT_ID', // Required. M2M OAuth client ID.
clientSecret: 'YOUR_CLIENT_SECRET', // Required. M2M OAuth client secret.
timeout: Duration(seconds: 30), // Optional. Request timeout. Default: 30s.
httpClient: http.Client(), // Optional. Custom HTTP client for testing.
);| Option | Type | Required | Description |
|---|---|---|---|
domain | String | Yes | Your tenant domain (e.g., myapp.auth.ing). |
clientId | String | Yes | Machine-to-machine OAuth client ID from the dashboard. |
clientSecret | String | Yes | Machine-to-machine OAuth client secret. |
timeout | Duration | No | Request timeout. Default: 30 seconds. |
httpClient | http.Client | No | Custom HTTP client for testing or proxying. |
User Management
Create User
final user = await client.users.create(
CreateUserRequest(
email: '[email protected]',
name: 'Jane Doe',
userMetadata: {'plan': 'pro'},
),
);
print('Created user: ${user.id}');List Users
// List with pagination and search
final users = await client.users.list(
page: 1,
perPage: 20,
q: 'jane',
);
for (final user in users.data) {
print('${user.id}: ${user.name} (${user.email})');
}
print('Total: ${users.total}');Get User
final user = await client.users.get('usr_abc123');
print('Name: ${user.name}');
print('Email: ${user.email}');
print('Logins: ${user.loginsCount}');
print('Last login: ${user.lastLogin}');Update User
final user = await client.users.update(
'usr_abc123',
UpdateUserRequest(
name: 'Jane Smith',
blocked: false,
appMetadata: {'tier': 'enterprise'},
),
);
print('Updated: ${user.name}');Delete User
Deletes a user and all their associated passkeys.
await client.users.delete('usr_abc123');Block / Unblock User
// Block a user (prevents authentication)
await client.users.update(
'usr_abc123',
UpdateUserRequest(blocked: true),
);
// Unblock a user
await client.users.update(
'usr_abc123',
UpdateUserRequest(blocked: false),
);Get User Roles
final roleIds = await client.users.getRoles('usr_abc123');
for (final roleId in roleIds) {
print('Role: $roleId');
}Credential Management
List Credentials
List passkey credentials, optionally filtered by user ID.
// List all credentials (optionally filtered by user)
final credentials = await client.credentials.list(
userId: 'usr_abc123',
page: 1,
perPage: 20,
);
for (final cred in credentials.data) {
print('${cred.id}: ${cred.name} (${cred.type.value})');
print(' Last used: ${cred.lastUsedAt}');
}Get Credential
final cred = await client.credentials.get('cred_xyz789');
print('Type: ${cred.type.value}');
print('User: ${cred.userId}');Delete Credential
Revoke a specific passkey credential.
await client.credentials.delete('cred_xyz789');Client / App Management
Create Client
final app = await client.clients.create(
CreateClientRequest(
name: 'My Mobile App',
appType: AppType.native,
callbacks: ['myapp://callback'],
allowedOrigins: ['https://myapp.com'],
),
);
print('Client ID: ${app.clientId}');List Clients
final apps = await client.clients.list();
for (final app in apps.data) {
print('${app.clientId}: ${app.name} (${app.appType.value})');
}Rotate Secret
final newSecret = await client.clients.rotateSecret('pk_live_abc123');
print('New secret: $newSecret');Role Management
Create Role
final role = await client.roles.create(
CreateRoleRequest(
name: 'admin',
description: 'Administrator role',
),
);
print('Role ID: ${role.id}');Assign and Remove Users
// Assign users to a role
await client.roles.assignUsers('role_abc123', ['usr_abc123', 'usr_def456']);
// List users in a role
final userIds = await client.roles.listUsers('role_abc123');
for (final userId in userIds) {
print('User: $userId');
}
// Remove users from a role
await client.roles.removeUsers('role_abc123', ['usr_def456']);Tenant Settings
Read and update tenant-level configuration such as session lifetimes, branding, and support contact.
// Get tenant settings
final settings = await client.tenant.get();
print('Tenant: ${settings.tenantName}');
print('Domain: ${settings.domain}');
print('Environment: ${settings.environment.value}');
print('Session lifetime: ${settings.sessionLifetime}s');
// Update tenant settings
final updated = await client.tenant.update(
UpdateTenantSettingsRequest(
tenantName: 'My App (Production)',
supportEmail: '[email protected]',
sessionLifetime: 86400,
),
);Audit Logs
Query audit logs for authentication events, user changes, and administrative actions.
// List recent log entries
final logs = await client.logs.list(
page: 1,
perPage: 50,
userId: 'usr_abc123',
type: 'login_success',
fromDate: '2025-01-01T00:00:00Z',
);
for (final entry in logs.data) {
print('${entry.date}: ${entry.type} from ${entry.ip}');
if (entry.description != null) {
print(' ${entry.description}');
}
}
// Get a single log entry
final entry = await client.logs.get('log_abc123');Enrollment Tokens
Generate tokens for enrolling a passkey for an existing user. The SDK supports two approaches: client-side signed JWTs (no network call) and server-side enrollment tickets. See the Enrollment guide for the full flow.
Client-Side Token (HMAC-SHA256)
Creates a signed JWT locally using the client secret. No API call required.
// Create an enrollment token (signed locally with HMAC-SHA256)
final token = client.enrollment.createToken(
userId: 'usr_abc123',
email: '[email protected]',
expiresIn: 300, // 5 minutes (default)
);
print('Token: $token');
// Return this token to your frontend for passkey enrollmentServer-Side Enrollment Ticket
Creates an enrollment ticket via the Management API with a redirect URL.
// Or create a server-side enrollment ticket via the API
final ticket = await client.users.createEnrollmentTicket('usr_abc123');
print('Ticket URL: ${ticket.url}');
print('Expires at: ${ticket.expiresAt}');gRPC Transport
The Dart SDK defines a PasskeyBaseGrpcClientabstract interface for a future gRPC-based transport. Currently all communication uses the REST/JSON HTTP client.
// The Dart SDK defines a PasskeyBaseGrpcClient interface for future
// gRPC transport support. Currently all communication uses REST/JSON.
//
// The gRPC interface mirrors the REST API:
//
// abstract class PasskeyBaseGrpcClient {
// Future<PaginatedResponse<User>> listUsers({int? page, int? perPage});
// Future<User> getUser(String userId);
// Future<User> createUser({required String email, String? name});
// // ... all other management operations
// Future<void> close();
// }
//
// A concrete implementation will be provided in a future release.Error Handling
All API errors throw typed exceptions extendingPasskeyBaseException. Use Dart's on clauses for granular error handling.
import 'package:passkeybase/passkeybase.dart';
final client = PasskeyBaseClient(
domain: 'myapp.auth.ing',
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
);
try {
final user = await client.users.get('usr_nonexistent');
} on NotFoundException catch (e) {
print('Not found: ${e.message}'); // "Not found"
print('Status: ${e.statusCode}'); // 404
} on AuthenticationException catch (e) {
print('Auth error: ${e.message}'); // "Unauthorized"
} on RateLimitException catch (e) {
print('Rate limited. Retry after: ${e.retryAfter}s');
} on NetworkException catch (e) {
print('Network error: ${e.message}');
print('Cause: ${e.cause}');
} on ApiException catch (e) {
print('API error ${e.statusCode}: ${e.message}');
}| Exception | Description |
|---|---|
AuthenticationException | 401 Unauthorized -- invalid or expired credentials. |
NotFoundException | 404 Not Found -- the requested resource does not exist. |
RateLimitException | 429 Too Many Requests. Includes retryAfter in seconds. |
TokenExchangeException | OAuth2 token exchange failed during M2M authentication. |
UnexpectedApiException | Any other API error (5xx, 400, 403, etc.). |
NetworkException | Connection failure, DNS error, or timeout. Includes the underlying cause. |
Next steps
- Enrollment -- add passkeys to existing auth systems
- API Reference -- full Management API documentation
- Kotlin / Android SDK -- native Android passkey integration
- Swift / iOS SDK -- native iOS passkey integration
- Node.js SDK -- server-side SDK for Node.js backends