How to Set Up OIDC Authentication in RomM: A Complete Guide
Enable OIDC in RomM by setting OIDC_ENABLED=true and configuring your provider credentials in environment variables, then restart the services to activate the OpenID Connect login button.
RomM supports OpenID Connect (OIDC) as a first-class authentication method for seamless single sign-on (SSO) integration. When properly configured, the backend validates tokens from your identity provider using the OpenIDHandler class in backend/handler/auth/base_handler.py, automatically provisions users, and assigns roles based on OIDC claims. This guide explains how to set up OIDC authentication in RomM using environment variables and the underlying implementation.
How the OIDC Flow Works in RomM
The authentication process involves coordinated steps between the Vue frontend and Python backend. When a user clicks the OIDC login button in frontend/src/v2/components/Auth/OIDCButton.vue, the application redirects to the provider's authorization endpoint with the configured client ID, scopes, and OIDC_REDIRECT_URI.
After the provider authenticates the user and redirects back to RomM, the backend exchanges the authorization code for tokens. The OpenIDHandler.get_current_active_user_from_openid_token method in backend/handler/auth/base_handler.py validates the ID token, checks that the email is verified, and extracts the username using the OIDC_USERNAME_ATTRIBUTE claim (defaulting to preferred_username).
If the email does not exist in the database and OIDC_ALLOW_REGISTRATION is true, RomM creates a new user record with a randomly generated password. The handler also maps OIDC role claims to RomM roles (ADMIN or USER) based on your OIDC_CLAIM_ROLES configuration. Finally, the backend creates a signed session cookie using ROMM_AUTH_SECRET_KEY that the frontend consumes via the /api/me endpoint.
Required Environment Variables
All OIDC configuration is loaded from environment variables via the config manager. Add these entries to your .env file or Docker Compose environment:
OIDC_ENABLED: Set totrueto activate the OIDC subsystemOIDC_PROVIDER: Human-readable name displayed in the UI (e.g., "Keycloak")OIDC_CLIENT_ID: Your OIDC client identifier from the providerOIDC_CLIENT_SECRET: The client secret associated with your OIDC clientOIDC_REDIRECT_URI: Full callback URL (e.g.,https://my-romm.tld/auth/openid/callback)OIDC_USERNAME_ATTRIBUTE: Claim field containing the username (default:preferred_username)OIDC_ALLOW_REGISTRATION: Set totrueto auto-create users for unknown email addressesOIDC_CLAIM_ROLES: Optional claim name containing user role stringsOIDC_ROLE_ADMIN: Value in the role claim that grants ADMIN rightsOIDC_ROLE_EDITORandOIDC_ROLE_VIEWER: Legacy values that map to the USER roleROMM_AUTH_SECRET_KEY: Required secret for signing JWTs and session cookies (already required for standard auth)
These variables are imported at the top of backend/handler/auth/base_handler.py (lines 15-23) and control the behavior of the OpenIDHandler class.
Step-by-Step Setup Guide
-
Create an OIDC client in your Identity Provider (Keycloak, Auth0, Google Workspace, Azure AD, etc.) and set the redirect URI to match your
OIDC_REDIRECT_URIvalue exactly. -
Configure your RomM
.envfile with the OIDC variables listed above. -
Restart the RomM container to load the new environment variables.
-
Verify the login screen displays the "Login with [Provider]" button, which is conditionally rendered in
frontend/src/v2/views/Auth/Login.vuewhen OIDC is enabled. -
Test the authentication flow by clicking the OIDC button, authenticating with your provider, and verifying you are redirected back to RomM as the authenticated user.
-
Optional: Configure logout redirect by ensuring your provider supplies an
oidc_logout_urlclaim in the token, which RomM stores in theOIDCLogoutResponsemodel and uses when users click logout.
Code Implementation Details
Backend Token Validation
The core validation logic resides in backend/handler/auth/base_handler.py. The handler checks if OIDC_ENABLED is active, validates the email is verified, extracts the preferred username, and maps roles:
# backend/handler/auth/base_handler.py (excerpt)
class OpenIDHandler:
async def get_current_active_user_from_openid_token(self, token: Any):
if not OIDC_ENABLED:
return None, None
userinfo = token.get("userinfo")
if userinfo is None:
raise HTTPException(status_code=400, detail="Userinfo is missing from token.")
email = userinfo.get("email")
if email is None:
raise HTTPException(status_code=400, detail="Email is missing from token.")
# Verify email is confirmed
if not self._email_is_verified(userinfo):
raise HTTPException(status_code=400, detail="Email is not verified.")
# Extract username and map roles
username = userinfo.get(OIDC_USERNAME_ATTRIBUTE)
role = self._map_roles(userinfo)
# Create or update user record
user = db_user_handler.get_user_by_email(email)
if user is None:
if not OIDC_ALLOW_REGISTRATION:
raise HTTPException(status_code=403, detail="Registration disabled.")
user = db_user_handler.add_user(
User(username=username, email=email, role=role, hashed_password=str(uuid.uuid4()))
)
elif role != user.role:
user = db_user_handler.update_user(user.id, {"role": role})
if not user.enabled:
raise UserDisabledException
return user, userinfo
Frontend Integration
The login button is implemented in frontend/src/v2/components/Auth/OIDCButton.vue, which initiates the flow by calling the authentication store:
<!-- frontend/src/v2/components/Auth/OIDCButton.vue -->
<template>
<v-btn @click="login" :loading="loading">
{{ $t('login.login-oidc', { oidc: provider || 'OIDC' }) }}
</v-btn>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useAuthStore } from '@/stores/auth';
const provider = import.meta.env.VITE_OIDC_PROVIDER;
const loading = ref(false);
const auth = useAuthStore();
function login() {
loading.value = true;
auth.startOidcLogin();
}
</script>
Environment Configuration Example
# Core auth secret (required for all auth methods)
ROMM_AUTH_SECRET_KEY=super-secret-key
# OIDC configuration
OIDC_ENABLED=true
OIDC_PROVIDER=Keycloak
OIDC_CLIENT_ID=romm-client
OIDC_CLIENT_SECRET=xxxxxxxxxxxx
OIDC_REDIRECT_URI=https://my-romm.tld/auth/openid/callback
OIDC_USERNAME_ATTRIBUTE=preferred_username
OIDC_ALLOW_REGISTRATION=true
OIDC_CLAIM_ROLES=roles
OIDC_ROLE_ADMIN=admin
OIDC_ROLE_EDITOR=editor
OIDC_ROLE_VIEWER=viewer
Summary
- RomM supports OIDC through environment variables defined in
backend/handler/auth/base_handler.py - Set
OIDC_ENABLED=trueand configure provider credentials to activate the feature - The system validates tokens via
OpenIDHandler.get_current_active_user_from_openid_tokenand auto-provisions users whenOIDC_ALLOW_REGISTRATIONis enabled - Roles map from OIDC claims using
OIDC_CLAIM_ROLESand the specific role environment variables (OIDC_ROLE_ADMIN, etc.) - The frontend button in
OIDCButton.vueinitiates the flow, while theOIDCLogoutResponsemodel handles optional provider logout redirects
Frequently Asked Questions
What identity providers work with RomM OIDC?
Any standards-compliant OpenID Connect provider works, including Keycloak, Auth0, Google Workspace, Azure AD, and Okta. Configure the authorization endpoint and token endpoint in your provider settings, then map the client ID and secret into RomM's environment variables.
Why does RomM require ROMM_AUTH_SECRET_KEY for OIDC?
RomM uses this secret to sign the session cookies and JWT tokens after successful OIDC validation. This is required even when using external authentication to maintain secure session state between the frontend and backend API.
How do I map admin roles from my OIDC provider?
Set OIDC_CLAIM_ROLES to the claim name containing roles (e.g., "groups" or "roles"), then set OIDC_ROLE_ADMIN to the specific value that should grant administrator privileges (e.g., "admin" or "romm-admin"). Users with matching claims receive the ADMIN role in RomM, while other values map to USER or are ignored if not configured.
Can I disable local authentication when OIDC is enabled?
Currently, RomM supports both authentication methods simultaneously. The OIDC button appears alongside the standard login form when OIDC_ENABLED is true, allowing users to choose their preferred method. There is no configuration option to disable local authentication while OIDC is active.
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 →