This document describes how to manage admin roles in the Wanderer Backend application, including the bootstrap mechanism for creating the first admin user.
The application uses a role-based access control (RBAC) system with two roles:
- USER: Standard user role (default for all new users)
- ADMIN: Administrator role with elevated privileges
Since only admins can promote other users to admin, there's a special bootstrap mechanism to create the first admin user when no admins exist in the system.
Set the following environment variables or application properties:
# Username of the user to auto-promote to admin (if no admins exist)
bootstrap.admin.username=your-admin-username
# Enable/disable the bootstrap mechanism (default: true)
bootstrap.admin.enabled=true- Create a user account via the registration endpoint (
POST /api/1/auth/register) - Set the bootstrap username in your application configuration
- Restart the application - the bootstrap mechanism will automatically:
- Check if any admin users exist
- If no admins found and
bootstrap.admin.usernameis set, promote that user to admin - Log the promotion or any errors
services:
wanderer-auth:
image: wanderer-auth:latest
environment:
- BOOTSTRAP_ADMIN_USERNAME=admin
- BOOTSTRAP_ADMIN_ENABLED=trueapiVersion: v1
kind: ConfigMap
metadata:
name: wanderer-auth-config
data:
bootstrap.admin.username: "admin"
bootstrap.admin.enabled: "true"Set environment-specific secrets or variables in your GitHub repository settings:
- Navigate to Settings → Environments → Select environment (e.g.,
production,staging,dev) - Add the following environment variables:
| Variable | Description | Example |
|---|---|---|
BOOTSTRAP_ADMIN_USERNAME |
Username of the user to promote to admin | admin |
BOOTSTRAP_ADMIN_ENABLED |
Enable/disable bootstrap (default: true) | true |
Then reference them in your workflow:
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # Uses environment-specific variables
steps:
- name: Deploy to Kubernetes
env:
BOOTSTRAP_ADMIN_USERNAME: ${{ vars.BOOTSTRAP_ADMIN_USERNAME }}
BOOTSTRAP_ADMIN_ENABLED: ${{ vars.BOOTSTRAP_ADMIN_ENABLED }}
run: |
# Your deployment command here- Register user
adminvia/api/1/auth/register - Set
BOOTSTRAP_ADMIN_USERNAME=admin - Start the application
- User
adminis automatically promoted to ADMIN role - Login as
admin- JWT token will includeROLE_ADMIN
- Bootstrap mechanism skips promotion
- Existing admins can promote other users
- Application logs an error message
- No promotion occurs
- Create the user first, then restart
Once at least one admin exists, admins can promote/demote other users via REST API.
All admin endpoints require authentication with ROLE_ADMIN.
POST /api/1/admin/users/{userId}/promote
Authorization: Bearer <admin-jwt-token>Response:
204 No Content- User promoted successfully400 Bad Request- User not found or already has admin role401 Unauthorized- Not authenticated403 Forbidden- Not an admin
Example:
curl -X POST "http://localhost:8083/api/1/admin/users/550e8400-e29b-41d4-a716-446655440000/promote" \
-H "Authorization: Bearer eyJhbGc..."DELETE /api/1/admin/users/{userId}/promote
Authorization: Bearer <admin-jwt-token>Response:
204 No Content- User demoted successfully400 Bad Request- User not found or doesn't have admin role401 Unauthorized- Not authenticated403 Forbidden- Not an admin
Example:
curl -X DELETE "http://localhost:8083/api/1/admin/users/550e8400-e29b-41d4-a716-446655440000/promote" \
-H "Authorization: Bearer eyJhbGc..."GET /api/1/admin/users/{userId}/roles
Authorization: Bearer <admin-jwt-token>Response:
200 OK- Returns array of roles (e.g.,["USER", "ADMIN"])400 Bad Request- User not found401 Unauthorized- Not authenticated403 Forbidden- Not an admin
Example:
curl -X GET "http://localhost:8083/api/1/admin/users/550e8400-e29b-41d4-a716-446655440000/roles" \
-H "Authorization: Bearer eyJhbGc..."Response:
["USER", "ADMIN"]After a user is promoted to admin, their JWT token will include both roles:
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"username": "admin",
"roles": ["USER", "ADMIN"],
"iat": 1234567890,
"exp": 1234571490
}Important: Users must re-login after promotion/demotion for role changes to take effect in their JWT tokens.
- Secure the bootstrap username: Don't use obvious usernames like "admin" in production
- Disable bootstrap after first admin: Set
bootstrap.admin.enabled=falseafter creating your first admin - Use strong passwords: Enforce strong password requirements for admin accounts
- Regular audits: Periodically review admin users and demote inactive admins
- Separate admin accounts: Don't use admin accounts for day-to-day operations
Problem: Bootstrap admin user not promoted
Solutions:
- Check logs for error messages
- Verify user exists (registered via
/api/1/auth/register) - Verify
bootstrap.admin.usernamematches exact username - Ensure
bootstrap.admin.enabled=true - Restart the application
Logs to check:
INFO No admin users found. Attempting to bootstrap admin user: <username>
INFO Successfully promoted user '<username>' to admin as first admin user
ERROR Bootstrap admin user '<username>' not found
Problem: Admin endpoint returns 403 Forbidden
Solutions:
- Verify JWT token is valid and not expired
- Check token includes
ROLE_ADMINin roles claim - Re-login if recently promoted to refresh token
- Verify Authorization header format:
Bearer <token>
Problem: Promotion returns 400 "User already has admin role"
Solution: User is already an admin. Use GET /api/1/admin/users/{userId}/roles to verify roles.
Admin roles are stored in the user_credentials table:
CREATE TABLE user_credentials (
user_id UUID PRIMARY KEY,
password_hash VARCHAR(255) NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT true,
email VARCHAR(255) NOT NULL UNIQUE,
roles VARCHAR(1000) -- Stores roles as comma-separated string (e.g., "USER,ADMIN")
);Roles are serialized/deserialized using RolesConverter JPA converter.
Full API documentation is available via Swagger UI:
- Auth Service: http://localhost:8083/swagger-ui.html
Look for the "Admin" tag in the API documentation.
Version: 0.5.2+
Last Updated: 2026-02-22