This repository is a starter template for Phoenix v1.8 apps built with Ash, LiveView, and Oban. Use it as a foundation and tailor it to your project.
add a .env file (see .env.example for an example) to have all env variables in place.
- Run
mix deps.get - Run
mix compile - Run
mix template.setup MyNewAppThe task updates modules, OTP app name, file paths, Helm chart names and more. It then deletes itself, discards the template's git history and creates a fresh initial commit (pass--no-gitto keep the history). - Run
mix setupto install and set up dependencies - Run
mix precommitto update assets and localizations if necessary - Start the Phoenix endpoint with
mix phx.serveroriex -S mix phx.server - Visit http://localhost:4000
- Adapt the
.githubworkflow files to your needs - If you want to use the recommended deployment-repository-approach using argoCD, read here how to configure it and update the
.github/workflows/cicd.ymlaccordingly. - For further questions ask in the dev-community slack channel
- Admin Dashboard: http://localhost:4000/admin
- Oban Dashboard: http://localhost:4000/oban
- Dev Dashboard: http://localhost:4000/dev/dashboard
- Phoenix 1.8 + LiveView
- Ash framework with AshAuthentication and AshAdmin
- Oban and Oban Web
- Tailwind v4 and bun (no node/npm required)
- Dockerfile and Helm chart
- GitHub Actions CI
This template ships with magic link authentication plus an optional, IdP-agnostic OIDC strategy named :sso via AshAuthentication. It works with any spec-compliant OIDC provider — Microsoft Entra ID (M365) and Zitadel are the tested paths.
important: Before you can use the OIDC strategy, you need an OIDC client at your identity provider (an "app registration" in Entra ID, an "application" in Zitadel). If you're doing this the first time or you don't have sufficient permissions, ask in the dev-community slack channel or your favourite CISO ;-)
OIDC SSO is a compile-time decision: when OIDC_ENABLED=true at build time, the :sso strategy (and its sign-in button) is compiled into the User resource; otherwise it does not exist and the sign-in page offers magic link only. Apps run either with OIDC or without — toggling it requires a rebuild (OIDC_ENABLED is a Docker build arg).
Environment variables (set OIDC_ENABLED identically at build time and runtime; when enabled, all required variables must be set at runtime — a mismatch fails the boot):
OIDC_ENABLED:trueto compile in and enable OIDC SSO, unset/falseto disable itOIDC_ISSUER: issuer/base URL, used for OIDC discoveryOIDC_CLIENT_ID: OIDC client idOIDC_CLIENT_SECRET: OIDC client secretOIDC_REDIRECT_URI: callback URL, e.g.https://myapp.example.com/auth/user/sso/callbackOIDC_TRUSTED_AUDIENCES(optional): comma-separated extra audiences trusted during ID token validation, beyond the client id
Provider notes:
- Microsoft Entra ID (M365):
OIDC_ISSUERishttps://login.microsoftonline.com/<tenant-id>/v2.0. No trusted audiences needed. App roles assigned in the app registration arrive as a standardroleslist claim and are mapped toUser.roles. Entra ID may omit theemailclaim depending on account type — ensure theemailclaim is configured, since registration upserts on email. - Zitadel:
OIDC_ISSUERis your Zitadel domain. SetOIDC_TRUSTED_AUDIENCESto the Zitadel project id. Project roles arrive under theurn:zitadel:iam:org:project:rolesclaim and are mapped toUser.roles.
High level flow:
- Entry point:
/sign-in-> Sign in with SSO - OIDC endpoints are generated by
AshAuthentication.Phoenixunder/auth - Strategy config lives in
Accounts.Userasoidc :sso - On callback, AshAuthentication validates state and nonce, then upserts the user
sequenceDiagram
autonumber
actor U as User (Browser)
participant A as YourApp (Phoenix/AshAuthentication)
participant P as OIDC Provider (Entra ID, Zitadel, ...)
participant I as External IdP
U->>A: GET /sign-in
A-->>U: Sign-in UI
U->>A: GET /auth/user/sso
A->>P: Redirect to authorization endpoint
P-->>U: Redirect to login
alt User authenticates with External IdP
U->>P: Choose IdP
P->>I: Redirect for authentication
I-->>P: Auth response
end
P-->>U: Redirect back to callback (code + state)
U->>A: GET /auth/user/sso/callback
A->>P: Token exchange
P-->>A: id_token + access_token
A->>A: Validate ID token and upsert user
A-->>U: Set session and redirect