Authentication
This guide covers authentication methods for the Kumiho Dart SDK.
Overview
Kumiho Cloud uses Firebase Authentication for identity management. The authentication flow works as follows:
User authenticates with Firebase via email/password
Firebase issues an ID token
SDK exchanges the token with Kumiho Control Plane
Control Plane returns tenant info and a region-scoped JWT
SDK connects to the appropriate regional server
Token Sources
Kumiho authenticates with a Bearer token attached to every gRPC call. The client loads the token in the following order:
A token provided directly to
KumihoClientvia thetokenargumentThe
KUMIHO_AUTH_TOKENenvironment variableCredentials cached by
kumiho-auth loginat~/.kumiho/kumiho_authentication.json
You can disable automatic loading by setting autoLoadToken: false when constructing KumihoClientBase.
CLI Authentication
The simplest way to authenticate is using the CLI:
kumiho-auth login
This prompts for your Kumiho Cloud email and password in the terminal. After successful login, credentials are cached in ~/.kumiho/kumiho_authentication.json.
Cached Credentials
The cached credentials include:
Firebase refresh token (for automatic token renewal)
Control Plane JWT (region-scoped access token)
Token expiration times
// SDK automatically uses cached credentials
final client = KumihoClient(
host: 'api.kumiho.io',
port: 443,
);
Refreshing Tokens
To manually refresh an expired token:
kumiho-auth refresh
Programmatic Authentication
With Explicit Token
If you have a Control Plane JWT (e.g., from a web app or mobile app):
final client = KumihoClient(
host: 'api.kumiho.io',
port: 443,
token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVC...',
);
With Environment Variables
For CI/CD pipelines and containerized deployments:
export KUMIHO_AUTH_TOKEN="your-control-plane-jwt"
// SDK reads from environment automatically
final client = KumihoClient(
host: 'api.kumiho.io',
port: 443,
);
Environment Variables
The SDK recognizes several environment variables for authentication behavior:
Variable |
Description |
|---|---|
|
Primary token, overrides anything stored in the credentials file |
|
When |
|
Prefer the control-plane token if present in cached credentials |
|
Grace period before expiry that triggers refresh (default |
Token Refresh
Automatic refresh is opt-in via KUMIHO_ENABLE_AUTO_REFRESH. When enabled, the client:
Loads cached credentials from
~/.kumiho/kumiho_authentication.jsonMonitors token expiration
Refreshes tokens when they approach expiry (within grace period)
Updates the Bearer token used in subsequent requests
You can also force a refresh attempt regardless of expiry state:
await client.forceRefreshToken();
Manual Token Updates
Set client.token at runtime to replace the active Bearer token. This is useful when:
Rotating tokens in long-lived applications
Swapping between user sessions
Implementing custom token refresh logic
// Update token at runtime
client.token = 'new-jwt-token';
Flutter Authentication
For Flutter applications, you might want to integrate with Firebase Auth directly:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:kumiho/kumiho.dart';
Future<KumihoClient> createAuthenticatedClient() async {
// Get Firebase ID token
final user = FirebaseAuth.instance.currentUser;
final idToken = await user?.getIdToken();
if (idToken == null) {
throw Exception('User not authenticated');
}
// Exchange for Kumiho Control Plane JWT
// (Implement your exchange logic here)
final controlPlaneJwt = await exchangeToken(idToken);
return KumihoClient(
host: 'api.kumiho.io',
port: 443,
token: controlPlaneJwt,
);
}
Error Handling
Authentication errors surface as GrpcError instances. Common scenarios:
try {
await client.getProjects();
} on GrpcError catch (e) {
if (e.code == StatusCode.unauthenticated) {
// Token is invalid or expired
await client.forceRefreshToken();
} else if (e.code == StatusCode.permissionDenied) {
// Token lacks required permissions
print('Access denied: ${e.message}');
}
}
Security Best Practices
Never commit tokens: Use environment variables or secure credential storage
Use short-lived tokens: Enable auto-refresh for production deployments
Secure storage: On mobile/desktop, use platform-specific secure storage
Rotate tokens regularly: For service accounts, implement token rotation