Authentication Setupπ
This guide provides the steps required to configure your OAuth 2.0 / OpenID Connect (OIDC) identity provider so the Apheris Hub can validate JWTs and support multi-user deployments. After completing the provider configuration here, continue with the Docker Deployment Guide or the Kubernetes Deployment Guide depending on how you deploy the Hub.
Identity Provider Requirementsπ
Your identity provider must meet the following requirements:
- OIDC Discovery: Exposes
{domain}/.well-known/openid-configurationso the Hub can discover the JWKS endpoint - JWKS Endpoint: Publishes a JWKS (JSON Web Key Set) for token signature verification
- JWT Token Format: Issues JWT access tokens with enough standard claims to identify users
- Required Token Claims:
iss(issuer): Must match what the Hub expects as issuer (hub.auth.issuerwhen set, otherwisehub.auth.domain)aud(audience): Must include the value configured as the Hub audience (hub.auth.audience) so tokens are intended for the Hub APIemail: Used for user identification and data segregation, so it must be present in the access tokenexp: Token expiration timestamp
- Optional but recommended claims (used for a better user experience in the UI):
namegiven_namefamily_name
The Hub has been tested with Auth0, Microsoft Entra (Azure AD), and Dex. Other OIDC-compliant providers should be supported but have not been validated.
General Configurationπ
The Hub learns about your identity provider through the hub.auth configuration block. The following fields are required for most providers, with issuer, extraScopes, and browserUrl only necessary when your provider requires them:
hub:
auth:
enabled: true
domain: "https://your-auth-domain/" # required
audience: "https://your-api-audience" # required
clientId: "your-client-id" # required
issuer: "https://issuer-if-different/" # optional (required for Microsoft Entra)
extraScopes: "optional:scope" # optional (required for Microsoft Entra)
browserUrl: "https://hub.example.com" # optional (internal IdP behind proxy/ingress)
Enabledπ
Controls whether the Hub enforces authentication and multi-user isolation.
- When
enabled: false, the Hub runs in single-user mode. Tokens are not required, and the otherhub.auth.*fields are ignored by the backend. - When
enabled: true, the Hub requires at leastdomain,audienceandclientIdto be set and will reject configuration that is incomplete or malformed.
Domainπ
hub.auth.domain is the base URL of your identity provider and is used to discover JWKS and metadata, and by the frontend as the OIDC authority.
- Always provide a full URL with scheme and trailing slash, for example:
- Auth0:
https://<tenant>.auth0.com/ - Microsoft Entra:
https://login.microsoftonline.com/<tenant-id>/v2.0/ - Dex (cluster DNS):
http://dex.dex.svc.cluster.local:5556/
- Auth0:
- If
enabled: trueanddomainis empty, the backend treats the configuration as invalid and will not accept requests using this auth setup. - For providers where the discovery base URL and issuer are identical (e.g., Auth0, Dex),
domainis sufficient; for providers where they differ (e.g., Entra), also configureissuer(see below).
Audienceπ
hub.auth.audience tells the Hub which API the access token must target.
- It must be an identifier, usually a URI or URL, that your identity provider issues tokens for. For example:
- Auth0:
https://hub.yourdomain.com/api - Microsoft Entra:
api://<client-id>
- Auth0:
- The backend validates that this value is present and has a URL scheme when auth is enabled. If
audienceis empty whileenabled: true, the Hub rejects the configuration. - Tokens that do not include this audience are rejected by the validator.
Client IDπ
hub.auth.clientId is the public client identifier of your Single Page Application (SPA), used by the browser when initiating the authorization code + PKCE (Proof Key for Code Exchange) flow. This value must be set correctly for the frontend to obtain tokens, see examples below for IdP-specific configurations.
Issuer (optional)π
hub.auth.issuer is the issuer URL the backend expects in the iss claim of access tokens.
- If
issueris empty, the backend usesdomainas the expected issuer. - For providers where the discovery URL and token issuer are the same (Auth0, Dex), you can leave this field empty.
- For providers where they differ (Microsoft Entra), set
hub.auth.issuerto the exact issuer in the token (for example,https://sts.windows.net/<tenant-id>/) while keepingdomainas the discovery URL. - If you set
issuer, it must be a valid URL with a scheme; otherwise the backend treats the configuration as invalid.
Extra Scopes (optional)π
hub.auth.extraScopes lets you request provider-specific scopes in addition to the default openid profile email offline_access.
- If empty, the frontend requests only the default scopes. Many providers (e.g., Auth0) will still issue an access token for your API when
audienceis set. - Some providers (notably Microsoft Entra) require you to request a specific API scope (for example,
api://<client-id>/<scope-name>) so the identity provider issues an access token with the expected audience. In those cases, use the scope name you configured on the provider side.
Browser URL (optional)π
hub.auth.browserUrl is only needed when the backend reaches the identity provider through an internal address that browsers cannot resolve (for example, Kubernetes cluster DNS) but users access the provider through a different, browser-friendly URL.
- When set, the Hub fetches the discovery document from
issuerand rewrites its URLs so the browser talks to thebrowserUrlhost that it can reach.- Typical use case: an internal IdP with issuer
https://idp.internal.svc.cluster.local/and an external proxy or ingress athttps://sso.example.com; setissuerto the internal URL andbrowserUrlto the public one.
- Typical use case: an internal IdP with issuer
- For Auth0 and Entra, where discovery uses public HTTPS endpoints reachable from the browser, leave
browserUrlempty and the frontend will use direct discovery.
Docker Deployment Demo Auth0π
The Docker deployment script deploy_apherisfold includes a proof-of-concept configuration that uses a shared Apheris-managed Auth0 tenant so you can try multi-user mode without configuring your own identity provider.
-
Set the following in your
config.yaml:config.yamlhub: auth: enabled: true domain: "" audience: "" clientId: ""
- When
enabled: trueand these fields are left empty, the script injects demo Auth0domain,audience, andclientIdvalues when starting the Hub container. - This mode is:
- Intended for localhost development only (ports 8080/8081).
- Shared across multiple users and environments.
When you are ready to use your own identity provider, replace the empty values with your real hub.auth.domain, hub.auth.audience, and hub.auth.clientId and follow the Auth0, Microsoft Entra, or Dex sections below.
Auth0 Guideπ
- Create the SPA application
- Visit Applications β Applications β Create Application.
- Name it (e.g.,
ApherisFold) and choose Single Page Application. - Note the Domain and Client ID from the Settings tab (you will need them for
hub.auth.domainandhub.auth.clientId).
-
Configure allowed URLs
-
In the application settings, add your frontend URLs to Allowed Callback URLs, Allowed Logout URLs, and Allowed Web Origins. Example entries for localhost development:
http://localhost:8000 http://localhost:8000/login
-
-
Create the API
- Navigate to Applications β APIs β Create API.
- Set the name (e.g.,
ApherisFold API) and use a URL-like identifier such ashttps://fold.apheris.com/api. - Keep the signing algorithm at RS256.
- Authorize the SPA
- In the APIβs Machine to Machine Applications tab, authorize your SPA so it can request an access token for the API.
- Enable login methods
- Under Authentication β Connections, enable the identity providers you want (Database, Google, GitHub, Microsoft, etc.).
- Back in Applications β [Your SPA], toggle the desired connections so they appear on the login screen.
- Claims
- Auth0 already includes
emailclaim in both ID and access tokens, so no extra configuration is required.
- Auth0 already includes
Example configuration:
hub:
auth:
enabled: true
domain: "https://<tenant>.auth0.com/"
audience: "https://fold.apheris.com/api"
clientId: "<client-id>"
Auth0 deployments do not require issuer or extraScopes to be set since the discovery URL and token issuer are identical, and the audience is sufficient to obtain access tokens for your API.
Microsoft Entra (Azure AD) Guideπ
Use this section to configure Microsoft Entra (formerly Azure AD) as the OIDC provider for the Hub.
Microsoft Entra setupπ
- Register a SPA application
- In the Microsoft Entra admin center, go to Identity β Applications β App registrations β New registration.
- Enter a name (for example,
ApherisFold) and choose the supported account types. - Leave redirect URIs empty for now.
- Click Register.
- Configure the application as a SPA
- In Authentication (Preview), on the Redirect URI configuration tab, click Add Redirect URI.
- Select Single-page application.
- Add a redirect URI, for example
http://localhost:8000, matching the URL where your frontend is served. - Click Configure.
- Still in Authentication (Preview), on the Settings tab, enable Allow public client flows so the SPA can use the authorization code + PKCE flow to obtain access tokens.
- Click Save.
- Expose the API (audience and scope)
- In Expose an API, click Add a scope.
- Keep the default Application ID URI (
api://<client-id>). This becomes yourhub.auth.audience. Click Save and continue. - Set a Scope name (for example,
access) so the resulting full scope isapi://<client-id>/<scope-name>(for example,api://<client-id>/access). - Select Admins and users for who can consent, add a short Admin consent display name and Admin consent description, then click Add scope.
- Configure token claims
- Under Token configuration, click Add optional claim, choose token type Access, and select the email claim so the access token includes
email. - Optionally also add the
given_nameandfamily_nameclaims for a better user experience in the UI. - Confirm by granting consent and clicking Add.
- Under Token configuration, click Add optional claim, choose token type Access, and select the email claim so the access token includes
Hub configurationπ
On the Overview tab of your registered application, note the following values:
Application (client) ID: use this forhub.auth.clientId.Directory (tenant) ID: use this to build thehub.auth.domainandhub.auth.issuerURLs.Application ID URI: use this forhub.auth.audience.- When you click on
Application ID URI, you can see the full scope name you created earlier; use this forhub.auth.extraScopes(for example,api://<client-id>/access).
Example configuration:
hub:
auth:
enabled: true
domain: "https://login.microsoftonline.com/<tenant-id>/v2.0/"
issuer: "https://sts.windows.net/<tenant-id>/"
audience: "api://<client-id>"
clientId: "<client-id>"
extraScopes: "api://<client-id>/<scope-name>"
hub.auth.domain(https://login.microsoftonline.com/<tenant-id>/v2.0/) is the discovery URL used by both the frontend and backend to fetch metadata and JWKS.hub.auth.issuer(https://sts.windows.net/<tenant-id>/) is the expectedissclaim used by the backend for token validation. This differs from the discovery URL, so you must set it explicitly.hub.auth.audience(api://<client-id>) must match theaudclaim in access tokens issued for your API.hub.auth.clientIdis the public client identifier of your SPA application.hub.auth.extraScopesmust include the API scope you created so the frontend requests an access token for your API. Bothhub.auth.issuerandhub.auth.extraScopesare required when you integrate with Microsoft Entra.
Dex (Cluster OIDC Provider) Guideπ
Dex can act as a central OIDC provider inside your Kubernetes cluster, with traffic flowing through your existing ingress or gateway and the Hub integrating via standard OAuth2/OIDC.
Dex setupπ
-
Deploy Dex behind ingress or gateway
- Install Dex into the cluster (for example, via the official Helm chart).
- Expose it at a stable HTTPS URL, such as
https://sso.example.com/dex.
-
Set issuer
- Configure Dexβs Issuer to exactly match the external URL (for example,
https://sso.example.com/dex). - This value becomes the
issclaim in issued tokens and the base URL for OIDC discovery.
- Configure Dexβs Issuer to exactly match the external URL (for example,
-
Create a static client for the Hub
id: a client identifier for the Hub, for examplehttps://apherisfold.example.com/api.redirectURIs: the Hub URLs where users return after login, for example:https://apherisfold.example.comhttps://apherisfold.example.com/login
-
Configure identity sources and claims
- Connectors: Add connectors such as LDAP (Lightweight Directory Access Protocol), GitHub, or upstream OIDC providers so Dex can authenticate your users.
- Claims: Ensure access tokens issued to the Hub always include
email(required for multi-user isolation). Optionally also includename,given_name, andfamily_namefor a better user experience in the UI.
Hub configuration for Dexπ
With Dex exposed at https://sso.example.com/dex and the Hub UI/API reachable at https://apherisfold.example.com, configure hub.auth as follows:
hub:
auth:
enabled: true
domain: "https://sso.example.com/dex"
issuer: "https://sso.example.com/dex"
audience: "https://apherisfold.example.com/api"
clientId: "https://apherisfold.example.com/api"
In this setup:
domainandissuershould point to the same Dex URL. If you omitissuer, the Hub automatically falls back todomainas the expected issuer, which is the recommended configuration for Dex.- Dex uses the OAuth client ID as the
audclaim in issued tokens by default. Because the Hub validatesaudagainsthub.auth.audience, you must keephub.auth.clientIdandhub.auth.audienceidentical for Dex-based setups. - Both the Hub backend and the browser talk to Dex via the same public URL, so
browserUrlis not needed. Only setbrowserUrlwhen Dex is reachable via an internal URL from the Hub but via a different external URL from usersβ browsers (see below for the internal/external URL example).
If Dex is only reachable by the Hub over an internal cluster address (for example, https://dex.dex.svc.cluster.local:5556) but users reach it through a different external URL (for example, https://sso.example.com/dex via ingress), configure:
domainandissuerwith the internal URL (used to fetch discovery and JWKS).browserUrlwith the external URL, as described in the Browser URL section, so the discovery proxy rewrites URLs for the browser.
Next Stepsπ
After configuring your identity provider, return to the Docker Deployment Guide or the Kubernetes Deployment Guide to finish the deployment that matches your environment.