Key Format
Developer Keys use the following format: Prefix:dk_ (Developer Key)
Full format: dk_ + 32 URL-safe characters (generated using Python’s secrets.token_urlsafe(32))
Example: dk_abc123XYZ-_789def456ghi012jkl345
Total length: 35 characters (3 character prefix + 32 character key)
The
dk_ prefix is generated in the backend using secrets.token_urlsafe(32) for cryptographically strong randomness.Key Properties
- Hashing: Keys are hashed with SHA-256 before storage for security (
hashlib.sha256) - Prefix storage: First 8 characters + ”…” stored in
key_prefixfor identification (e.g.,dk_abc12...) - One-time display: The full key is shown once during generation; only the hash is persisted
- Developer scoping: Each key is bound to a specific developer account via
developer_id(UUID) - Active status: Keys can be revoked by setting
is_activeto false - Database model: Stored in
developer_keystable with columns:id,developer_id,key_hash,key_prefix,name,is_active,last_used_at,created_at,updated_at
Managing Developer Keys
Accessing the Developer Keys Page
Navigate to Developer Keys from the Cloud Admin console sidebar:- Log in to Cloud Admin at devkit4ai.com/console or vibecoding.ad/console
- Click Developer Keys in the left sidebar
- View your existing keys and their usage statistics
Creating a New Developer Key
1
Open Generation Dialog
Click the Generate Key button in the top right corner
2
Enter Key Name
Enter an optional descriptive name (max 255 characters) like “Production API” or “Staging Environment” to help identify the key’s purpose
3
Generate and Copy
Click Generate and immediately copy the full key. This is your only chance to see the complete key!
4
Store Securely
Save the key in your environment variables or secret management system
Backend Implementation Flow
- Frontend calls
POST /api/v1/auth/developer-keyswith optionalnameparameter - Backend validates developer role via
validate_developer_role() GenerateDeveloperKeyCommandis sent to command bus withdeveloper_id,name, andmax_keys=10GenerateDeveloperKeyHandlerloads user aggregate from event storeUserActions.generate_developer_key()validates:- User role is DEVELOPER
- Active key count < 10 (raises ValueError if limit reached)
DeveloperKey.generate_developer_key()static method generates:key_suffix = secrets.token_urlsafe(32)full_key = f"dk_{key_suffix}"key_hash = hashlib.sha256(full_key.encode("utf-8")).hexdigest()key_prefix = full_key[:8] + "..."
DeveloperKeyWasGeneratedevent is raised withdeveloper_key_id,developer_id,key_hash,key_prefix,name- Event is persisted to event store
UserReadModelprojector handles event and createsDeveloperKeyrecord in database- Full key is returned in
DeveloperKeyCreatedResponse(only time it’s available) - Key becomes valid immediately for API requests
Viewing Key Details
Each key in the list displays:- Name: Descriptive label you provided (or null)
- Key Prefix: First 8 characters + ”…” (e.g.,
dk_abc12...) for identification - Created: ISO 8601 timestamp when the key was generated
- Last Used: Most recent authentication timestamp (or null if “Never used”)
- Active Status: Boolean flag (
is_active) - Actions: Revoke button
Revoking a Developer Key
To revoke a key:- Locate the key in the Developer Keys list
- Click the Revoke button in the Actions column
- Confirm the revocation in the dialog
- The key is immediately deactivated
Backend Revocation Flow
- Frontend calls
DELETE /api/v1/auth/developer-keys/{key_id}with JWT token - Backend validates:
- Developer role via
validate_developer_role() - Key exists and belongs to current developer via database query
- Returns 404 if key not found or doesn’t belong to developer
- Developer role via
RevokeDeveloperKeyCommandis sent to command bus withdeveloper_idanddeveloper_key_idRevokeDeveloperKeyHandlerloads user aggregate from event storeUserActions.revoke_developer_key()validates:- Key exists in aggregate’s
developer_keysdict (raises ValueError if not found) - Key is not already revoked (raises ValueError if already revoked)
- Key exists in aggregate’s
DeveloperKeyWasRevokedevent is raised withdeveloper_key_idanddeveloper_id- Event is persisted to event store
UserReadModelprojector handles event and setsis_active=FalseonDeveloperKeyrecord- Endpoint returns 204 No Content on success
- Future authentication attempts with revoked key fail
Key Limits
Each developer account is limited to 10 active keys at a time.Limit Enforcement
The limit is enforced inUserActions.generate_developer_key():
- Counts active keys:
sum(1 for is_active in self.developer_keys.values() if is_active) - Raises
ValueErrorwith message ifactive_key_count >= max_keys - Error message: “Maximum number of developer keys (10) reached. Please revoke an existing key before creating a new one.”
- Constant defined in
app/features/auth/api/endpoints.py:MAX_DEVELOPER_KEYS_PER_DEVELOPER = 10
- The Generate Key button displays “Limit Reached (10/10)”
- Backend returns 400 Bad Request with error message
- Revoke unused keys before creating new ones
- Consider which keys are no longer needed by checking last usage dates
Managing Key Limits
Best practices for staying within limits:- Regular Audits: Review your keys monthly and revoke unused ones
- Descriptive Names: Use clear names to identify key purposes
- Environment-Based: Use one key per environment (dev, staging, prod)
- Application-Based: Separate keys for different applications or services
- Team Member Keys: Individual keys for team members who need API access
Use Cases
Local Development
Use a development-specific key for local testing:CI/CD Pipelines
Create a dedicated key for automated deployments:Team Member Access
Issue individual keys for team members working with the API:- Frontend Developer: Key for Starter Kit development
- Backend Developer: Key for API integration testing
- DevOps Engineer: Key for deployment automation
Multi-Environment Setup
Separate keys for each environment:Environment Variable
In your Starter Kit or Cloud Admin deployment, set the generated key as:Database Schema
Developer keys are stored in thedeveloper_keys table:
- No foreign key constraints (event-sourced architecture pattern)
- Relationship defined in SQLAlchemy:
developer = relationship("User", primaryjoin="foreign(DeveloperKey.developer_id)==User.id")
Security
Security Implementation
- Hashing algorithm: SHA-256 (
hashlib.sha256) - Random generation:
secrets.token_urlsafe(32)(cryptographically strong) - Storage: Only hash and prefix stored in database, never plain text
- Validation: Via
app/system/auth/rbac.py::validate_developer_key() - Request state: Validated key attaches
developer_idanddeveloper_key_idtorequest.state

