How to Set Up OAuth2 Authentication in RomM: Complete Implementation Guide
RomM implements a full OAuth 2.0 flow with password-grant, refresh-grant, and optional OpenID Connect (OIDC) support through environment variables in backend/config.py and token handlers in backend/handler/auth/base_handler.py.
Setting up OAuth2 authentication in RomM requires configuring environment variables for token signing and enabling specific endpoints that handle JWT issuance and validation. The implementation supports both traditional password-based authentication and external identity providers via OIDC, with Redis-backed refresh token rotation for enhanced security.
Prerequisites and Configuration
Before enabling OAuth2 flows, you must set the required environment variables in backend/config.py. These values control token lifetimes and cryptographic signing:
ROMM_AUTH_SECRET_KEY– The HMAC-SHA256 key used to sign all JWT tokensOAUTH_ACCESS_TOKEN_EXPIRE_SECONDS– Lifetime of short-lived access tokensOAUTH_REFRESH_TOKEN_EXPIRE_SECONDS– Lifetime of longer-lived refresh tokens
RomM loads these configurations at startup and uses them across the authentication stack.
Token Architecture
The core OAuth2 logic resides in backend/handler/auth/base_handler.py within the OAuthHandler class. This implementation uses JWT tokens with specific claims and Redis storage for one-time-use semantics.
Access Token Generation
The OAuthHandler.create_access_token method generates short-lived JWTs containing:
type = "access"claim- Configurable expiration based on
OAUTH_ACCESS_TOKEN_EXPIRE_SECONDS
Refresh Token Management
The OAuthHandler.create_refresh_token method issues longer-lived tokens with:
type = "refresh"claim- A unique JTI (JWT ID) stored in Redis for single-use enforcement
When consuming refresh tokens, OAuthHandler.consume_refresh_token validates the JTI, removes it from Redis to prevent reuse, and returns the associated user object.
API Endpoints
All OAuth2 HTTP routes are defined in backend/endpoints/auth.py.
Password Grant Flow
The POST /token endpoint supports grant_type=password. It validates credentials via auth_handler.authenticate_user, verifies requested scopes against user.oauth_scopes, and returns both access and refresh tokens.
curl -X POST "$BASE_URL/api/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password&username=john&password=secret&scope=roms.read roms.write"
Refresh Token Flow
For grant_type=refresh_token, the endpoint calls consume_refresh_token, invalidates the old refresh token JTI, and issues a fresh token pair while preserving the original scopes.
curl -X POST "$BASE_URL/api/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&refresh_token=<REFRESH_TOKEN>"
OpenID Connect Integration
RomM supports OIDC for external authentication providers. When OIDC_ENABLED is set, the following endpoints become active:
GET /login/openid– Initiates the authentication flowGET /oauth/openid– Handles the provider callback, validates tokens viaOpenIDHandler, and provisions users
The callback endpoint validates the external token, creates a session, and redirects to the UI with RomM tokens.
Device and Session Management
Upon successful authentication (password or OIDC), RomM automatically manages device sessions through utils.auth.create_or_find_web_device. This function creates or reuses browser device records and stores the device ID in the session, enabling multi-device tracking and session management.
Security Implementation
The OAuth2 implementation in RomM includes several security controls:
Token Signing: All tokens are signed using ROMM_AUTH_SECRET_KEY loaded as a jose OctKey in base_handler.py.
One-Time Use Refresh Tokens: The JTI values for refresh tokens are stored in Redis and immediately deleted upon consumption in consume_refresh_token, preventing replay attacks.
Scope Validation: The token endpoint verifies that requested scopes are a subset of the user's granted scopes (User.oauth_scopes) before issuing tokens.
Bearer Token Validation: The get_current_active_user_from_bearer_token method validates the iss = "romm:oauth" claim and token signature before returning the user.
Summary
- Configure OAuth2 in RomM by setting
ROMM_AUTH_SECRET_KEY,OAUTH_ACCESS_TOKEN_EXPIRE_SECONDS, andOAUTH_REFRESH_TOKEN_EXPIRE_SECONDSenvironment variables - Access tokens are short-lived JWTs with
type="access"claims generated inbackend/handler/auth/base_handler.py - Refresh tokens use Redis-backed JTI storage for one-time-use semantics via
consume_refresh_token - Use
POST /tokenwithgrant_type=passwordfor initial authentication orgrant_type=refresh_tokenfor token rotation - Enable OIDC by setting
OIDC_ENABLEDand using the/login/openidand/oauth/openidendpoints - All authenticated requests require an
Authorization: Bearer <access_token>header validated against theiss = "romm:oauth"claim
Frequently Asked Questions
How do I configure the OAuth2 secret key in RomM?
Set the ROMM_AUTH_SECRET_KEY environment variable before starting the application. This key is used as the HMAC-SHA256 signing key for all JWT tokens and is loaded as a jose OctKey in backend/handler/auth/base_handler.py. Without this configuration, token generation and validation will fail.
What is the difference between access tokens and refresh tokens in RomM?
Access tokens are short-lived JWTs containing a type="access" claim that authorize API requests via the Authorization: Bearer header. Refresh tokens are longer-lived tokens with type="refresh" that include a unique JTI stored in Redis; they can only be used once to obtain new token pairs through the POST /token endpoint with grant_type=refresh_token.
How does RomM handle OpenID Connect authentication?
RomM implements OIDC through the GET /login/openid and GET /oauth/openid endpoints in backend/endpoints/auth.py. When enabled via OIDC_ENABLED, the login endpoint redirects to the external provider, and the callback endpoint validates the external token using OpenIDHandler, provisions the user if necessary, and establishes a session with device tracking via create_or_find_web_device.
Where are refresh tokens stored and how are they secured?
Refresh token JTI values are stored in Redis with the implementation enforcing one-time-use semantics. When consume_refresh_token processes a refresh request, it immediately removes the JTI from Redis, ensuring the token cannot be replayed. This prevents token theft and reuse attacks in the RomM authentication flow.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →