Skip to main content

Security & Authentication

FHIR ANT includes a full authentication and authorization system. In Dev Mode (the default for testing), authentication is bypassed. When Dev Mode is off, all non-public endpoints require a valid JWT token.

Dev Mode

When enabled, all requests are accepted without authentication. A synthetic admin user is injected into every request so that audit trails and scope enforcement still function internally.

Dev Mode is for testing only. A warning banner appears in the app when it's active.

Authentication Flow

Registration & Login

# Register a new user (first user becomes admin)
curl -X POST http://server:8080/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"mysecurepassword"}'

# Login
curl -X POST http://server:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"mysecurepassword"}'
# Returns: {"token": "eyJ...", "refresh_token": "eyJ...", ...}

Using Tokens

# Use the access token for authenticated requests
curl -H "Authorization: Bearer eyJ..." http://server:8080/Patient

Token Refresh

curl -X POST http://server:8080/auth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"refresh_token","refresh_token":"eyJ..."}'

OAuth 2.0 Authorization Code Flow (PKCE)

FHIR ANT supports the full OAuth 2.0 authorization code flow with PKCE, suitable for SMART on FHIR applications:

  1. GET /auth/authorize — Authorization endpoint
  2. POST /auth/authorize — Submit authorization (JSON or form-encoded)
  3. POST /auth/token — Exchange code for tokens (with code_verifier)

Token Revocation (RFC 7009)

# Revoke a token
curl -X POST http://server:8080/auth/revoke \
-H "Content-Type: application/json" \
-d '{"token":"eyJ..."}'

# Logout (revokes access token from Authorization header)
curl -X POST http://server:8080/auth/logout \
-H "Authorization: Bearer eyJ..."

SMART on FHIR Scopes

FHIR ANT enforces SMART v2 scope syntax: context/resourceType.permissions

ContextExampleDescription
useruser/Patient.rsUser-level read+search on Patient
patientpatient/Observation.crudsPatient-level full access
systemsystem/*.*System-level full access (admin)

Permissions: c (create), r (read), u (update), d (delete), s (search)

Default Scopes by Role

RoleDefault Scopes
adminsystem/*.*
clinicianuser/*.*
readonlyuser/*.rs

Password Policy

Follows NIST 800-63B guidelines:

  • Minimum 12 characters, maximum 128
  • No complexity rules (length > complexity)
  • Blocked common passwords (e.g., "password123456")
  • Case-insensitive blocklist matching

Account Lockout

  • Account locks after 5 failed login attempts
  • Auto-unlock after 15 minutes
  • Admin can manually unlock via POST /admin/unlock/<userId>
  • Returns HTTP 423 (Locked) when account is locked

Database Encryption

The SQLite database is encrypted with SQLCipher. The encryption key is generated on first launch and stored in the device's secure keystore (Android Keystore / iOS Keychain). Data at rest is always encrypted.

Audit Trail

All requests are logged with timestamp, method, path, status code, duration, client IP, and authenticated user (if present).