SSO Reference¶
Last Updated: November 11, 2026
Overview¶
MaxIOFS supports Single Sign-On (SSO) via OAuth2/OIDC providers. Users authenticate with their external identity provider (Google, Microsoft, etc.) and are either auto-provisioned or pre-authorized by an administrator.
Supported providers: Google Workspace, Microsoft Entra ID (Azure AD), and any custom OAuth2/OIDC provider.
Key principle: SSO users log in with their email address as their MaxIOFS username. This avoids username collisions between different identity providers.
One email, one user: an email belongs to one MaxIOFS user, as its username or as its email, local, LDAP or SSO. Creating, editing, importing, syncing or provisioning a user with an email another user has is refused: 409 in the console, email_conflict at sign-in. Case does not count. Providers can repeat (two tenants with Google); emails cannot.
How SSO Login Works¶
- User clicks the "Sign in with Google" (or Microsoft, etc.) button on the login page
- User enters their email address
- MaxIOFS redirects to the identity provider with the email pre-filled (
login_hint) - User authenticates with the provider
- The provider redirects back to MaxIOFS with the user's profile (email, name, groups)
- MaxIOFS searches all configured OAuth providers to check if the user is authorized (see Authorization Model)
- If authorized, the user is logged in. If it's their first login, an account is automatically created
Setup Guide¶
Step 1: Create the Identity Provider¶
- Go to Users → Identity Providers
- Click Add Provider
- Select OAuth2 as the type
- Fill in the provider configuration:
Google Workspace¶
| Field | Value |
|---|---|
| Name | |
| Preset | |
| Client ID | From Google Cloud Console |
| Client Secret | From Google Cloud Console |
| Redirect URI | https://your-maxiofs-domain/api/v1/auth/oauth/callback |
| Scopes | openid email profile |
| Service account key | The JSON key of the service account that reads the directory (optional) |
Google Cloud Console setup:
1. Create a new OAuth 2.0 Client ID (Web application)
2. Add the redirect URI: https://your-maxiofs-domain/api/v1/auth/oauth/callback
3. Enable the Google People API
Group mappings and Auto Sync need the directory: Google's userinfo gives no groups. 1. Enable the Admin SDK API in the Google Cloud project. 2. Create a service account and a JSON key for it. It needs no domain-wide delegation. 3. In the Google Admin console, make an administrator role that only reads users and groups, and assign it to the service account by its email. 4. Paste the JSON key in Service account key. MaxIOFS keeps it encrypted and does not show it again. 5. Name each group in its mapping by its email. Only direct members count: the members of a group inside it do not.
Microsoft Entra ID (Azure AD)¶
| Field | Value |
|---|---|
| Name | Microsoft |
| Preset | Microsoft |
| Client ID | From Azure Portal |
| Client Secret | From Azure Portal |
| Redirect URI | https://your-maxiofs-domain/api/v1/auth/oauth/callback |
| Scopes | openid email profile |
| Issuer URL | https://login.microsoftonline.com/<tenant-id>/v2.0 |
Azure Portal setup:
1. Register a new application in Azure AD
2. Add the redirect URI as a Web platform redirect
3. Create a client secret under "Certificates & secrets"
4. Under "API Permissions", add Microsoft Graph: openid, email, profile
Group mappings and Auto Sync need the directory: Microsoft's userinfo gives no groups.
1. Set the Issuer URL with the tenant's ID, not a domain. Only that tenant can then sign in.
2. Under "API Permissions", add the application permissions User.Read.All and GroupMember.Read.All of Microsoft Graph, and grant an administrator's consent. MaxIOFS reads with the client's own ID and secret.
3. Name each group in its mapping by its Object ID. The members of a group inside it count too.
Keycloak (or another OpenID Connect provider)¶
| Field | Value |
|---|---|
| Preset | Custom |
| Client ID / Client Secret | Of a confidential client of the realm |
| Authorization / Token / UserInfo URL | https://keycloak/realms/<realm>/protocol/openid-connect/auth, /token, /userinfo |
| Groups claim | groups, with a Group Membership mapper on the client (full group path off) |
| Issuer URL | https://keycloak/realms/<realm> |
Keycloak client setup:
1. Valid redirect URI: https://your-maxiofs-domain/api/v1/auth/oauth/callback
2. Once the provider is saved, its settings show the Back-channel logout URL (https://your-maxiofs-domain/api/v1/auth/oauth/<provider-id>/backchannel-logout). Set it as the client's Backchannel logout URL, with Backchannel logout session required on.
3. For Auto Sync: turn on the client's Service accounts roles, and give its service account the role view-users of the client realm-management. MaxIOFS reads the realm's users and groups with the client's own credentials.
4. A user's Email verified must be on: MaxIOFS refuses an email the provider says it did not verify (email_not_verified). Keycloak leaves it off for a user an administrator creates; a user who registers verifies it by email.
Step 2: Test the Connection¶
- Click the plug icon next to the provider in the list
- Each step shows whether it passed, warned or failed, and what it found. A warning is a configuration that works but lacks something.
| Step | What it checks |
|---|---|
| Discovery | With an Issuer URL: the provider's OpenID configuration and its signing keys |
| Sign-in page | The provider shows its sign-in page for the Client ID and the Redirect URI. A client it does not know, or a redirect URI the client does not have, fails here |
| Client secret | An invented code is exchanged at the token URL. invalid_grant means the provider took the Client ID and secret; invalid_client or unauthorized_client means it refused them |
| Userinfo | The userinfo URL asks for a token |
The steps run together and take at most 15 seconds. A missing field fails the test before the provider is asked.
For an LDAP provider the steps run in order, and a step that fails stops the ones that need it:
| Step | What it checks |
|---|---|
| Connection | Host and port, over TLS for LDAPS. A connection without TLS warns: the passwords cross the network in clear |
| StartTLS | With StartTLS: the directory starts TLS with a certificate the server trusts |
| Service account | The bind DN and password |
| Users | The user search base and filter find users; a warning when none has the username attribute |
| Groups | The group search base and filter. A base that does not exist fails, since a sign-in searches it; no group found warns |
Step 3: Authorize Users¶
Choose one or both methods described in the Authorization Model below.
Authorization Model¶
There are two ways to authorize which users can log in via SSO. You can use either or both.
Option A: Group-Based Access (Auto-Provisioning)¶
Best for: Authorizing entire teams or departments. Users are automatically created on first login.
- Go to Identity Providers → (your provider) → Group Mappings (tree icon)
- Click Add Mapping
- Enter the external group identifier:
- Google: Group email (e.g.,
engineering@yourcompany.com) - Microsoft: Group Object ID or display name
- Select the MaxIOFS role for members of this group:
admin— Full access including user managementuser— Standard access to buckets and objectsreadonly— View-only access- Optionally enable Auto Sync: the provider's directory is then read every hour (see Directory Sync). Membership is checked again at each sign-in and renewal (see Sessions Follow the Provider).
How it works: When a user authenticates via SSO, MaxIOFS checks if they belong to any mapped group. If they do, an account is automatically created with: - Username = their email address - Role = the role from the matching group mapping - Tenant = the provider's tenant
If the user belongs to multiple mapped groups, the highest-privilege role wins (admin > user > readonly).
Example:
Group Mapping: engineering@company.com → role: user
Group Mapping: platform-admins@company.com → role: admin
User: alice@company.com (member of engineering@company.com)
→ Auto-provisioned with role: user
User: bob@company.com (member of both groups)
→ Auto-provisioned with role: admin (highest privilege)
User: stranger@gmail.com (not in any mapped group)
→ Rejected: "You are not authorized to access this system"
Option B: Individual User Access (Manual Import)¶
Best for: Authorizing specific people without needing group infrastructure.
- Create the user manually in Settings → Users → Create User:
- Username: The user's email address (e.g.,
juan@gmail.com) - Role: The desired role
- Password: Leave empty (SSO users don't use passwords)
- Auth Provider: Set to
oauth:{provider-id}(the provider ID is shown in the Identity Providers list) -
External ID: The user's email address
-
Or use LDAP Browser (for OAuth providers that support user search):
- Go to Identity Providers → (your provider) → Browse Users (users icon)
- Search for the user
- Click Import
How it works: When the user authenticates via SSO, MaxIOFS finds the account of that email under the provider that signed them in, and logs them in directly. No auto-provisioning needed.
Combining Both Methods¶
Both methods work together: - If a user is already imported manually, they log in immediately (SSO finds their existing account) - If a user is not imported but belongs to a mapped group, they are auto-provisioned on first login - If a user is neither imported nor in a mapped group, they are rejected
Sessions Follow the Provider¶
A console session of an SSO user is renewed every security.access_token_lifetime (15 minutes by default), and at each renewal MaxIOFS asks the provider again with the refresh token the provider gave at sign-in:
- The provider refuses the refresh (user deleted or disabled, provider session ended): the console session ends.
- A user made by a group mapping gets the role its groups map to now; in no group mapped any more, the session ends and the user cannot sign in again. A user an administrator made keeps the role given; to make one follow its groups, edit the user and tick Follows the provider's groups.
- The provider cannot be reached: the session is kept, as long as the console's own
security.session_timeout. - In a cluster only the node that started the session uses the provider's refresh token: the other nodes pass its renewals there, and renewals that arrive together, as from several tabs, share one refresh. A provider with refresh token rotation (Keycloak's Revoke Refresh Token) refuses a second use of a refresh token and ends its own session. While that node does not answer, the node reached keeps the session without asking the provider; once it is removed from the cluster, the coordinator renews its sessions. An LDAP session is asked about on the node reached.
- With the Issuer URL and the back-channel logout URL set in the provider, a sign-out there, or an administrator ending the user's sessions there, ends the console sessions of that sign-in at once.
Google gives a refresh token only on the first consent of a user: later sign-ins cannot be asked about again, and end with the console's own session. A sign-out in MaxIOFS ends the session on every node.
Directory Sync¶
A user who never signs in to the console, such as one who uses access keys only, is not asked about at a renewal. The directory sync asks for them: every hour, on the coordinator in a cluster, MaxIOFS reads the directory of each active provider with a mapping set to Auto Sync: an LDAP directory, a Keycloak realm, a Google Workspace or a Microsoft tenant. Sync All in the provider's group mappings reads it at once and says what it did.
- The members of the mappings set to Auto Sync that have no user get one, following their groups.
- Each user of the provider is asked about as at a renewal: with the service account in LDAP, through the admin API in Keycloak, the Directory API in Google and Microsoft Graph in Microsoft. A user gone from the directory or disabled there, suspended or archived in Google, or in Keycloak whose email is not verified, is deactivated: no console, no access keys. A user that follows its groups gets the role they map to now, and is deactivated in no group mapped.
- A user the sync deactivated is activated again once the directory lets it in. A user an administrator deactivated stays so.
- A directory that does not answer changes nobody.
Users are deactivated, never deleted: a configuration mistake, such as a wrong user search base, is undone by the next sync after it is fixed. A Keycloak provider is one whose Issuer URL names a realm (https://keycloak/realms/<realm>), a Microsoft provider one whose Issuer URL names a tenant, and a Google provider one with a service account key. Another OAuth provider gives no members and cannot be asked about a user without the user's sign-in: Sync All says it has no directory.
Test Connection reads one user of the directory, and warns when it cannot: sign-ins work without it.
With Google and Microsoft a sign-in and a renewal read the user's groups from the directory too. If the directory refuses, a sign-in goes on without groups: only a user who needs them is refused. A renewal keeps the session. Microsoft Graph answers a group's members from an index, so a new member may take a moment to appear; the groups of a user are read at once.
Login Page Behavior¶
SSO Buttons¶
When OAuth providers are configured and active, the login page shows one button per provider type below the standard username/password form (e.g., "Sign in with Google", "Sign in with Microsoft"). Even if multiple tenants configure the same provider type (e.g., multiple Google Workspace configurations), only one "Sign in with Google" button is shown.
When the user clicks an SSO button, they are prompted to enter their email address. MaxIOFS uses this email to:
- Pre-fill the provider's login page (login_hint)
- Determine which provider configuration to use (if multiple exist for the same type)
Email Detection¶
If a user types an email address in the username field and submits the login form:
- MaxIOFS detects the @ symbol and suggests using the SSO button instead
- The SSO buttons section is visually highlighted
If an existing SSO user tries to log in with username/password: - MaxIOFS returns a message directing them to use the SSO button
Role Priority¶
When a user matches multiple authorization rules, the highest-privilege role is assigned:
- admin (highest)
- user
- readonly (lowest)
Error Messages¶
| Error | Meaning | Solution |
|---|---|---|
not_in_authorized_group |
User authenticated but is not in any authorized group and has no manual account | Admin must either add the user's group as a group mapping, or create the user manually |
no_group_mappings |
No group mappings are configured and user has no manual account | Admin must configure at least one group mapping or create the user manually |
email_conflict |
The email belongs to another user: local, LDAP, or of another provider | Admin must resolve the conflict (change the other account's email or delete it) |
missing_email |
The OAuth provider did not return an email address | Check provider configuration and user's account settings |
email_not_verified |
The provider says it did not verify the user's email (email_verified false): anyone may have typed it there |
Verify the email at the provider; in Keycloak, turn on the user's Email verified |
provisioning_failed |
Auto-provisioning failed (database error) | Check server logs for details |
oauth_denied |
User cancelled the SSO login | User should try again |
exchange_failed |
The provider refused the code or the token | Check the client ID, the client secret and the redirect URI |
provider_unavailable |
The provider could not be reached, answered with a server error, or did not answer within 15 seconds | Check provider status and network connectivity |
account_inactive |
The user's account exists but is deactivated | Admin must reactivate the account |
account_locked |
Too many failed login attempts | Wait for the lockout period to expire |
Multi-Tenant Configuration¶
Each identity provider can be scoped to a specific tenant: - Global providers (no tenant): Available to all tenants - Tenant-scoped providers: Only users in that tenant can use the provider
A tenant-scoped provider gives users of its tenant only: auto-provisioning, import and sync put them in the provider's tenant, whatever tenant a mapping or an import names. A tenant administrator sees, tests, browses, imports from and maps groups of its own tenant's providers only.
Multiple Tenants with the Same Provider Type¶
Multiple tenants can each configure their own Google (or Microsoft) OAuth provider. For example:
- Tenant A: Google OAuth for companyA.com Workspace
- Tenant B: Google OAuth for companyB.com Workspace
The login page shows a single "Sign in with Google" button. When the user enters their email and authenticates: 1. MaxIOFS sends the user to the provider that has an account for that email; with none, to the first of that type by name 2. Only that provider signs the user in: its account for that email, or, with none, an account its own group mappings give 3. A provisioned user goes into that provider's tenant
A new email therefore reaches the first provider of its type only. For the users of the others, create or import them before their first sign-in. No tenant information is exposed on the login page.
Important Notes¶
- SSO users cannot use password login — they must always use the SSO button
- One account per email — an email belongs to one user; see Key principle
- LDAP users are unaffected — LDAP authentication continues to work with username/password
- Local users are unaffected — standard username/password login works as before
- 2FA is supported — SSO users can enable two-factor authentication after their first login. With it enabled, the console asks for the code after the provider's sign-in: the exchanged code gives the second step's token, sent with the code to
/api/v1/auth/2fa/verify - Existing imported users continue to work — if users were imported before auto-provisioning was available, they still log in normally