PasskeyBase
D

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.

← All SDKs


Installation

Add the package from pub.dev:

Terminal
dart pub add passkeybase

Requirements: 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.

main.dart
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

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.
);
OptionTypeRequiredDescription
domainStringYesYour tenant domain (e.g., myapp.auth.ing).
clientIdStringYesMachine-to-machine OAuth client ID from the dashboard.
clientSecretStringYesMachine-to-machine OAuth client secret.
timeoutDurationNoRequest timeout. Default: 30 seconds.
httpClienthttp.ClientNoCustom HTTP client for testing or proxying.

User Management

Create User

Create a 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 users with pagination
// 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

Get a user by ID
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

Update a 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.

Delete a user
await client.users.delete('usr_abc123');

Block / Unblock User

Block and unblock
// 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

Get roles for a user
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 credentials
// 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

Get a credential by ID
final cred = await client.credentials.get('cred_xyz789');
print('Type: ${cred.type.value}');
print('User: ${cred.userId}');

Delete Credential

Revoke a specific passkey credential.

Delete a credential
await client.credentials.delete('cred_xyz789');

Client / App Management

Create Client

Create an OAuth 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

List OAuth clients
final apps = await client.clients.list();
for (final app in apps.data) {
  print('${app.clientId}: ${app.name} (${app.appType.value})');
}

Rotate Secret

Rotate client secret
final newSecret = await client.clients.rotateSecret('pk_live_abc123');
print('New secret: $newSecret');

Role Management

Create Role

Create a role
final role = await client.roles.create(
  CreateRoleRequest(
    name: 'admin',
    description: 'Administrator role',
  ),
);
print('Role ID: ${role.id}');

Assign and Remove Users

Manage role membership
// 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.

Tenant settings
// 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.

Query audit logs
// 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 enrollment token
// 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 enrollment

Server-Side Enrollment Ticket

Creates an enrollment ticket via the Management API with a redirect URL.

Create enrollment ticket
// 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.

gRPC interface (future)
// 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.

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}');
}
ExceptionDescription
AuthenticationException401 Unauthorized -- invalid or expired credentials.
NotFoundException404 Not Found -- the requested resource does not exist.
RateLimitException429 Too Many Requests. Includes retryAfter in seconds.
TokenExchangeExceptionOAuth2 token exchange failed during M2M authentication.
UnexpectedApiExceptionAny other API error (5xx, 400, 403, etc.).
NetworkExceptionConnection failure, DNS error, or timeout. Includes the underlying cause.

Next steps