Skip to content

feat: add Azure AD (Entra ID) SSO login provider#4428

Open
kent-hydra wants to merge 6 commits into
hatchet-dev:mainfrom
kent-hydra:feat/azure-sso
Open

feat: add Azure AD (Entra ID) SSO login provider#4428
kent-hydra wants to merge 6 commits into
hatchet-dev:mainfrom
kent-hydra:feat/azure-sso

Conversation

@kent-hydra

Copy link
Copy Markdown

Description

Adds Azure AD / Microsoft Entra ID as a first-class SSO login provider, alongside the existing Google and GitHub OAuth providers. Built on the same golang.org/x/oauth2 rails — no new dependencies — and modeled directly on the Google/GitHub sibling implementations.

Fixes #4427

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update (included)

What's Changed

  • Config (SERVER_AUTH_AZURE_*): enabled / clientID / clientSecret / tenantID / scopes, mirroring SERVER_AUTH_GOOGLE_*. tenantID is optional — defaults to the organizations meta-tenant (multi-tenant), or set it to lock sign-in to a single directory.
  • OAuth client (pkg/auth/oauth): NewAzureClient builds tenant-templated authorize/token endpoints (login.microsoftonline.com/{tenant}/oauth2/v2.0/...).
  • Endpoints: GET /api/v1/users/azure/start and /callback, added to the OpenAPI spec and registered in rbac.yaml as public (no-auth) operations.
  • Callback: reads identity from the Microsoft OIDC userinfo endpoint (sub/name/email); domain restriction reuses checkUserRestrictionsForEmail (email-domain based, since Azure AD has no hd claim). OAuth tokens are encrypted at rest like the other providers.
  • Metadata: /api/v1/meta advertises azure when the provider is enabled.
  • Frontend: an "Azure" button on the login page + the corresponding query wrappers.
  • Docs: SERVER_AUTH_AZURE_* documented in the self-hosting configuration reference.

Checklist

Changes have been:

  • Tested (manually — full local docker compose deployment with a successful end-to-end sign-in against a real Azure AD tenant; also verified /api/v1/meta advertises azure and /api/v1/users/azure/start 302-redirects to the correct Microsoft authorize URL)
  • Linted and formatted (gofmt, go vet; frontend prettier/eslint on changed files)
  • Documented (self-hosting configuration reference)
  • Added to CHANGELOG — repo uses git-cliff / conventional commits, so leaving the changelog to the release tooling

Notes for reviewers

  • Roughly half the diff is regenerated code (api/v1/server/oas/gen/openapi.gen.go, pkg/client/rest/gen.go, frontend Api.ts / data-contracts.ts) produced by task generate-api after the OpenAPI spec change.
  • frontend/app/src/lib/api/generated/control-plane/Api.ts was hand-edited to add the two cloudUserUpdateAzureOauth* methods, because the control-plane client is generated from a separate spec that has no regeneration path in this repo. Happy to adjust if there's a preferred approach.
  • One implementation note validated against the Microsoft docs: the oidc/userinfo endpoint returns neither email_verified nor preferred_username, so the callback sets EmailVerified=true deliberately (the email is directory-sourced, and the authz middleware rejects unverified users — matching the Google/GitHub providers' behavior).

🤖 AI Disclosure
  • I acknowledge that an LLM was used in the creation of this Pull Request, in accordance with Hatchet's AI_POLICY.md.

  • Details: Claude Code (Claude Opus 4.8) was used to implement the feature end-to-end — modeled on the existing Google/GitHub OAuth providers — to run the OpenAPI codegen, to verify it via a local Docker deployment against a real Azure AD tenant, and to draft this PR. All changes were reviewed by the author.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

@kent-hydra is attempting to deploy a commit to the Hatchet Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added documentation Improvements or additions to documentation engine Related to the core Hatchet engine dashboard Related to the Hatchet dashboard labels Jul 14, 2026
kent-hydra and others added 6 commits July 15, 2026 10:01
Add the Azure (Entra ID) OAuth provider as a sister to the existing
Google/GitHub providers:

- NewAzureClient builds the oauth2.Config with tenant-templated
  authorize/token endpoints (login.microsoftonline.com/{tenant}/...),
  defaulting to the "organizations" meta-tenant when no tenant is set.
- ConfigFileAuthAzure adds the enabled/clientID/clientSecret/scopes
  fields plus an Azure-specific optional tenantID, wired via the
  SERVER_AUTH_AZURE_* env vars.
- The loader constructs AzureOAuthConfig when enabled and includes
  "azure" in the security-check provider list.
- "azure" is accepted by the OAuthOpts provider validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the /api/v1/users/azure/start and /callback endpoints to the OpenAPI
spec, regenerate the server/client code, and implement the handlers:

- azure_oauth_start.go mirrors the Google start handler (save state,
  redirect to AuthCodeURL).
- azure_oauth_callback.go exchanges the code, reads claims from the
  Microsoft OIDC userinfo endpoint (graph.microsoft.com/oidc/userinfo),
  and upserts the user. Since Azure AD has no Google-style "hd" claim,
  domain restriction follows the GitHub pattern (check the email domain),
  with a preferred_username fallback when the email claim is absent.
- The /meta handler advertises "azure" when the provider is enabled.

Regenerated: openapi.gen.go, rest/gen.go, frontend Api.ts, data-contracts.ts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Render an "Azure" social auth button when the /meta endpoint reports the
"azure" scheme, mirroring the Google/GitHub buttons:

- Add a Microsoft logo icon and the azure entry to PROVIDER_CONFIG.
- Wire azureEnabled through the auth page provider list.
- Add the Azure start/callback query wrappers, including the
  control-plane variants used on Hatchet Cloud.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the SERVER_AUTH_AZURE_* environment variables to the self-hosting
configuration reference.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The API server validates at startup that every OpenAPI operation has an
authz classification in rbac.yaml, and panics otherwise. Add the Azure
OAuth start/callback operations to the public (no-auth) allowlist,
alongside the Google/GitHub equivalents, so the server boots with the
Azure endpoints registered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verified against Microsoft's docs that graph.microsoft.com/oidc/userinfo
returns only sub/name/.../email — it does NOT return preferred_username or
email_verified. Accordingly:

- Drop the dead preferred_username fallback and email_verified conditional
  (neither claim is ever present in the userinfo response).
- Collapse azureUserInfoResponse into a single azureUserInfo struct.
- Set EmailVerified=true explicitly, with a comment: the email is sourced
  from the Azure AD directory and Hatchet's authz middleware blocks
  unverified users, matching the Google/GitHub providers.
- Check the userinfo HTTP status so a Graph failure surfaces a clear error
  instead of masquerading as "azure account must have an email".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dashboard Related to the Hatchet dashboard documentation Improvements or additions to documentation engine Related to the core Hatchet engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Azure AD (Entra ID) SSO as a login provider

1 participant