Omada SAML to OIDC Bridge lets an Omada Controller accept OIDC login through SATOSA plus a small amount of custom routing and rewrite code. The public browser flow stays on OIDC, while the bridge turns that login into the SAML traffic Omada expects.
- The browser goes to the public Omada URL.
- The Omada launch route sends the browser into SATOSA.
- SATOSA authenticates the user through the configured OIDC provider.
- The bridge posts the SAML response back to Omada.
- The custom proxy layer rewrites public URLs so Omada keeps redirecting to the browser-facing hostname instead of an internal controller address.
- A public HTTPS hostname for the bridge
- A public HTTPS hostname for the OIDC provider
- One or more internal Omada controller endpoints
- Docker and Docker Compose
- An OIDC Identity Provider (IdP) such as Pocket ID or Authelia
These settings must be correct before the bridge will behave properly:
PUBLIC_BASE_URLmust be a publichttps://URL for the bridge itself.OIDC_PROVIDER_ISSUERmust be the publichttps://issuer URL for Pocket ID or Authelia.OMADA_PUBLIC_BASE_URLmust be the publichttps://URL users open for Omada.OMADA_UPSTREAM_BASESmust contain internal controller IPs or DNS names plus port, such ashttps://10.0.0.11:443,https://omada-node-2.internal:443.
Do not point OMADA_UPSTREAM_BASES at the public Omada hostname. The bridge uses those upstream values to reach the controller directly inside the network.
The compose example in examples/docker-compose.yml shows the bridge container. Copy omada-saml-oidc.env.example to omada-saml-oidc.env, fill in the Omada and OIDC values, and keep that file private.
image: ghcr.io/snuffy2/omada-saml-oidc:latestThe examples use generic hostnames:
bridge.example.comfor the public bridge hostnameomada.example.comfor the public Omada hostnameauth.example.comfor the IdPcontroller-1.internalfor the private Omada controller node
The compose file defines a shared omada Docker network so the bridge and the OIDC provider can talk to each other without exposing the controller upstreams to the public internet.
Pocket ID works well when you want a light OIDC provider that uses passkeys exclusively.
- Create an OIDC client for the bridge.
- Set
OIDC_PROVIDER_ISSUERto the public Pocket ID issuer URL. - Point the browser-facing Omada hostname at the bridge launch hostname.
Use examples/docker-compose.yml as the starting point, then attach Pocket ID to the same Docker network and point OIDC_PROVIDER_ISSUER at its public issuer URL.
Authelia is the right fit when you already use it as your main identity layer.
- Create an OIDC client for the bridge in Authelia.
- Set
OIDC_PROVIDER_ISSUERto the public Authelia issuer URL. - Keep the Authelia public URL on HTTPS.
- Route the Omada hostname to the ACS handler and the launch hostname to the bridge.
Use the same compose file, then attach Authelia to the same Docker network and point OIDC_PROVIDER_ISSUER at its public issuer URL.
Use examples/traefik-pocket-id.yml when Pocket ID is the OIDC provider, or examples/traefik-authelia.yml when Authelia is the OIDC provider.
Both files show the same public flow:
omada.example.com/redirects to the bridge launch pathbridge.example.com/launch/omadagoes to the bridge launcheromada.example.com/sso/saml/logingoes to the bridge ACS handler- The rest of the Omada hostname goes to the controller upstream
auth.example.comgoes to the OIDC provider
The public Omada hostname and the login hostname both stay on HTTPS.
Use examples/nginx-pocket-id.conf for Pocket ID or examples/nginx-authelia.conf for Authelia.
Both files show the same flow with nginx:
- Redirect
/to the bridge launch path bridge.example.com/launch/omadagoes to the bridge launcher- Proxy
/sso/saml/loginto the bridge - Proxy the remaining Omada traffic to the controller upstream
- Proxy the OIDC provider hostname to the IdP
Use nginx when you want the routing rules in one place and prefer explicit server blocks over Traefik labels.
omada-saml-oidc.env.exampleexamples/docker-compose.ymlexamples/traefik-pocket-id.ymlexamples/traefik-authelia.ymlexamples/nginx-pocket-id.confexamples/nginx-authelia.conf
MIT. See LICENSE.