Auth Service
The Auth Service (auth_service) handles authentication, token management, and cryptographic operations for the FluxiQ SPB platform. It issues JWT tokens, manages refresh token rotation, and integrates with HSM for BACEN message signing.
Port: 4001
Responsibilities
- Authenticate users via username/password credentials
- Issue and validate JWT access tokens and refresh tokens
- Manage token revocation and blacklisting
- Provide mTLS certificate validation for inter-service communication
- Integrate with HSM (Hardware Security Module) for BACEN digital signatures
- Support multi-factor authentication (MFA) for privileged operations
Authentication Flow
Client API Gateway Auth Service Database
| | | |
| POST /auth/login | | |
|---------------------->| | |
| | Forward credentials | |
| |---------------------->| |
| | | Verify password |
| | |------------------>|
| | |<------------------|
| | | |
| | | Generate JWT + |
| | | Refresh Token |
| |<----------------------| |
| { token, refresh } | | |
|<----------------------| | |JWT Token Structure
Access tokens contain the following claims:
json
{
"sub": "user-uuid",
"iss": "fluxiq-spb",
"aud": "fluxiq-spb-api",
"exp": 1706000000,
"iat": 1705996400,
"tenant_id": "institution-uuid",
"ispb": "12345678",
"roles": ["operator", "treasury"],
"permissions": [
"transactions:read",
"transactions:create",
"str:balance:read",
"settlements:read"
]
}Token lifetimes:
| Token Type | Default TTL | Configurable |
|---|---|---|
| Access Token | 1 hour | JWT_TTL env var |
| Refresh Token | 7 days | REFRESH_TTL env var |
| MFA Token | 5 minutes | MFA_TTL env var |
Configuration
elixir
# config/runtime.exs
config :auth_service, AuthService.Token,
secret_key: System.fetch_env!("JWT_SECRET"),
issuer: "fluxiq-spb",
ttl: {System.get_env("JWT_TTL", "3600") |> String.to_integer(), :seconds},
refresh_ttl: {System.get_env("REFRESH_TTL", "604800") |> String.to_integer(), :seconds}
config :auth_service, AuthService.HSM,
provider: System.get_env("HSM_PROVIDER", "softHSM"),
slot: System.get_env("HSM_SLOT", "0"),
pin: System.get_env("HSM_PIN"),
key_label: System.get_env("HSM_KEY_LABEL", "bacen-signing-key")
config :auth_service, AuthService.MFA,
enabled: System.get_env("MFA_ENABLED", "true") == "true",
issuer: "FluxiQ SPB",
totp_period: 30API Endpoints
Login
bash
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "operator@institution.com.br",
"password": "secure-password"
}
# Response 200
{
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZn...",
"expires_in": 3600,
"token_type": "Bearer"
}
}Refresh Token
bash
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refresh_token": "dGhpcyBpcyBhIHJlZn..."
}
# Response 200
{
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "bmV3IHJlZnJlc2ggdG9r...",
"expires_in": 3600,
"token_type": "Bearer"
}
}Refresh tokens follow a rotation policy: each use issues a new refresh token and invalidates the previous one. If a previously-used refresh token is presented, all tokens for that user session are revoked (replay detection).
Token Revocation
bash
POST /api/v1/auth/revoke
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"token": "eyJhbGciOiJIUzI1NiIs..."
}
# Response 200
{
"data": {"revoked": true}
}MFA Setup
bash
POST /api/v1/auth/mfa/setup
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# Response 200
{
"data": {
"secret": "JBSWY3DPEHPK3PXP",
"qr_code_uri": "otpauth://totp/FluxiQ%20SPB:user@institution.com.br?secret=JBSWY3DPEHPK3PXP&issuer=FluxiQ%20SPB",
"backup_codes": ["12345678", "23456789", "34567890", "45678901", "56789012"]
}
}MFA Verification
bash
POST /api/v1/auth/mfa/verify
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"code": "123456"
}
# Response 200
{
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"mfa_verified": true
}
}Password Policy
Passwords must meet BACEN security requirements:
- Minimum 12 characters
- At least one uppercase letter, one lowercase letter, one digit, and one special character
- Cannot match the last 12 passwords
- Expires after 90 days
- Account locks after 5 failed attempts (unlocks after 30 minutes)
HSM Integration
The auth_service manages HSM operations for BACEN message signing:
elixir
defmodule AuthService.HSM do
@doc "Signs a BACEN XML message using the institution's private key"
def sign_message(xml_content) do
with {:ok, session} <- open_session(),
{:ok, key} <- find_key(session, @key_label),
{:ok, signature} <- sign(session, key, xml_content) do
{:ok, Base.encode64(signature)}
end
end
@doc "Verifies a BACEN response signature using BACEN's public certificate"
def verify_signature(xml_content, signature, certificate) do
:public_key.verify(xml_content, :sha256, signature, certificate)
end
endHealth Check
bash
curl http://localhost:4001/health
# {"status": "ok", "hsm": "connected", "database": "connected"}