Skip to content

Sso azure auth0

Azure SSO (Auth0) - Implementation Notes

This document captures the key implementation details for our Azure Entra ID (SAML) SSO integration managed through Auth0, and how we persist configuration securely in our workspace settings.

Routes

  • Backend: frontend-logics/routes/sso/azure.py
  • POST /create_enterprise_connection
  • POST /update_enterprise_connection

Both routes are protected with our service-to-service (S2S) token validator so that a connectors access token is available at runtime:

  • Decorator (added to both routes):
  • @service_to_service_access_token_validator.validate_service_to_service_access_token(connectors_token_name, connectors_access_token_env_var_name, connectors_token_expiry_env_var_name, connectors_service_url)
  • The validator ensures the connectors S2S access token is fetched from the DB table services_access_tokens (token name configured as connectors_token_name) and exported into the process env under the name specified by connectors_access_token_env_var_name.

Connectors S2S token

  • DB table: services_access_tokens (columns: token_name, access_token, token_expiry, last_request_time)
  • Token used here is frontend_logics_to_connectors (see utils/authentication.py for the configured name).
  • After validation, read it with:
  • os.environ.get("CONNECTORS_ACCESS_TOKEN") (or equivalently os.environ.get(connectors_access_token_env_var_name), which resolves to the same env key).

PEM certificate handling

  • During create, we parse the uploaded federation metadata XML and obtain:
  • signInEndpoint (IdP SSO URL)
  • signingCert (PEM, as a string with BEGIN/END CERTIFICATE headers)

  • We then ENCRYPT the PEM before persisting it to workspace options:

  • Endpoint: POST {regional_connectors_url}/encrypt-string
  • Headers: Authorization: Bearer $CONNECTORS_ACCESS_TOKEN
  • Body: { "string": "<pem_cert_string>" }
  • On success: store encrypted_signing_cert in workspace options and NEVER store the raw PEM.
  • If the encryption request fails (e.g. token missing or transient error), we log to Sentry/Slack and proceed (connection creation is not blocked). In this case, encrypted_signing_cert is left null.

  • Relevant environment:

  • CONNECTORS_ACCESS_TOKEN (set by the S2S validator decorator)
  • Region selection for connectors URL: get_regional_connectors_url("besg") (adjust region if needed).

Auth0 connection options

When creating the SAML connection we send (subset):

  • signInEndpoint: URL from XML
  • signingCert: PEM from XML
  • entityId: urn:auth0:{tenant}:{connection_name}
  • signSAMLRequest: true
  • signatureAlgorithm: rsa-sha256
  • digestAlgorithm: sha256

Optionally (depending on product choice), we also set:

  • domain_aliases: ["<company_domain>"] when “Restrict login to SSO only for this domain” is enabled (HRD)
  • idpinitiated: { enabled: true, client_id: <AUTH0_APP_CLIENT_ID>, client_protocol: "oidc" }

We persist a snapshot of non-sensitive options under options.sso_connection.auth0_connection_options for audit/debugging.

Workspace options persisted

Under options.sso_connection we store:

  • provider: "azure_ad"
  • company_domain
  • connection_name
  • entity_id
  • acs_url
  • sign_in_url
  • metadata_file_name
  • restrict_sso_only (boolean)
  • encrypted_signing_cert (encrypted PEM; may be null if encryption failed)
  • auth0_connection_options (subset of applied options; no secrets)

Updating the connection

  • Important Auth0 behavior: PATCHing the SAML connection options requires the body to satisfy required fields (e.g. signingCert). If we send only partial options omitting required fields, Auth0 may return:
  • {"statusCode":400,"error":"Bad Request","message":"The signing certificate public key is required","errorCode":"invalid_body"}

  • Our update route builds a minimal connection_options and only includes fields we are changing:

  • If XML is provided: update signInEndpoint, signingCert, and set protocolBinding.
  • If “Restrict SSO only” is toggled: update domain_aliases (when restricting and we know the effective domain). We mirror the state locally in workspace options.
  • We do NOT rename the connection on update (Auth0 blocks renames for enterprise SAML).

Known constraints

  • If we need to PATCH options that trigger strict validation in Auth0 and we are not sending the PEM, be aware that Auth0 may require signingCert to be present. The safe approach when toggling unrelated options is to either:
  • Merge existing options (including signingCert) on the server side before PATCH, or
  • Limit the PATCH body to fields that Auth0 allows changing without revalidating signingCert.

Frontend behavior

  • The “Restrict login to SSO only for this domain” toggle:
  • Sends restrict_sso_only (and we couple this with the signing toggle when needed).
  • Allows saving without uploading XML.

  • On creation, user must upload the federation metadata XML and provide the company domain.

Logging and failures

  • PEM encryption failures are logged to Sentry and Slack, but do not block the flow.
  • Auth0 Management API errors are surfaced back to the caller with the response body for visibility.