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
Enter Key Name
Enter an optional descriptive name (max 255 characters) like “Production API” or “Staging Environment” to help identify the key’s purpose
Generate and Copy
Click Generate and immediately copy the full key. This is your only chance to see the complete key!
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

