Set Up Single Sign-On with authentik
Deploy authentik as an IdP and wire Grafana to it using OAuth2/OIDC.
Introduction
30 Second Summary
Every time you click "Sign in with Google" or "Log in with SSO" at work, an Identity Provider is doing the heavy lifting behind the scenes.
In this project, you will deploy authentik as a self-hosted Identity Provider, wire it up to Grafana using OAuth2/OpenID Connect, and test a full SSO login flow from end to end.
What You'll Build
A local SSO environment where authentik acts as the Identity Provider and Grafana acts as the relying party, all running in local Docker containers.
By the end of this project, you'll have:
- A running authentik stack (server, worker, PostgreSQL, Redis) deployed via Docker Compose.
- An OAuth2/OIDC provider and application configured in authentik, with Grafana wired up as the relying party.
- A tested end-to-end SSO login flow where users authenticate through authentik and land in Grafana.
- A group-to-role mapping so authentik groups automatically control Grafana Admin, Editor, and Viewer roles via OIDC claims.
Are there any prerequisites?
You need Docker and Docker Compose installed on your machine. You should also be comfortable with basic command-line tools. The authentik stack requires a minimum of 2 CPU cores and 2 GB of RAM.
Download and Configure the authentik Stack
Before you can configure SSO, you need a running Identity Provider. In this step, you'll deploy authentik locally using Docker Compose. The stack includes four containers: the authentik server, a background worker, PostgreSQL for persistent storage, and Redis for caching.
In This Step, Get Ready To:
- Download the official authentik Docker Compose file.
- Generate secrets and create the environment configuration.
- Start the full authentik stack and verify all containers are healthy.
Download the Official Compose File
authentik publishes a maintained Docker Compose file that defines all four services and their networking. Downloading this file directly ensures you're working with a tested, version-pinned configuration.
- Create a new project directory and navigate into it.
mkdir ~/authentik-project && cd ~/authentik-project
- Download the compose file.
macOS
curl -O https://docs.goauthentik.io/compose.yml
Linux
wget https://docs.goauthentik.io/compose.yml
Windows
curl -O https://docs.goauthentik.io/compose.yml
What does this command do?
This downloads the official compose.yml from authentik's documentation site. The file defines four services: server (the main authentik web server), worker (background task processing), postgresql (database), and redis (cache). It also pins a specific authentik version rather than using :latest, which has been deprecated and frozen at the 2025.2 release.
Generate Secrets and Create the .env File
The compose file expects two secrets via environment variables: a PostgreSQL password and an authentik secret key. You'll generate both with openssl and write them to a .env file that Docker Compose reads automatically.
- Generate the PostgreSQL password and append it to .env.
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
- Generate the authentik secret key and append it to .env.
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
- Verify that both values are populated.
cat .env
What should I see?
You should see two lines, each with a long random string. The PG_PASS value uses a 36-byte key (kept under PostgreSQL's 99-character password limit). The AUTHENTIK_SECRET_KEY uses a longer 60-byte key for signing sessions and tokens.
Start the authentik Stack
With the compose file and secrets in place, you can pull the container images and bring up the stack.
- Pull all required images.
docker compose pull
What does this command do?
This downloads the authentik, PostgreSQL, and Redis images from their registries. The total download is approximately 1.5 GB, so it may take a few minutes depending on your connection speed.
- Start all containers in detached mode.
docker compose up -d
- Verify all containers are running and healthy.
docker compose ps
What should I see?
You should see four containers listed: server, worker, postgresql, and redis. All should show a status of "Up" or "healthy". The server container exposes ports 9000 (HTTP) and 9443 (HTTPS).
- Follow the server logs to confirm authentik has finished starting up.
docker compose logs -f server
Wait until you see the gunicorn startup message in the logs. This indicates the authentik server is ready to accept requests. Press Ctrl+C to stop following the logs once you see it.
Containers not starting?
Make sure your system meets the minimum requirements of 2 CPU cores and 2 GB RAM. Also verify that ports 9000 and 9443 are not already in use by another process. If the worker container keeps restarting, check its logs with docker compose logs worker. Help me troubleshoot my authentik containers.
Your Identity Provider is up and running. Next up, you'll create the admin account and explore the authentik admin interface.
Complete Initial Setup and Explore the Admin Interface
Your authentik stack is running, but it does not have an admin account yet. Before you can configure SSO, you need to complete the initial setup flow and familiarize yourself with the Admin interface where you will create providers, applications, users, and groups.
In This Step, Get Ready To:
- Create the initial admin account through authentik's setup flow.
- Explore the Admin interface and understand authentik's key sections.
Create the Admin Account
authentik ships with a one-time initial setup flow that creates the first admin user. This flow is only available before any admin account exists.
- Open http://localhost:9000/if/flow/initial-setup/ in your browser.
- Enter an admin email address and a strong password for the akadmin account.
- Click Submit.
After submitting, you are logged in and redirected to the authentik user interface.
Pro tip: trailing slash matters
The trailing slash in the setup URL is required. Without it, you will get a 404 error.
Page Not Loading?
If the setup page does not load, the server container may still be starting up. Run docker compose logs -f server and wait for the gunicorn startup message before retrying. Help me troubleshoot the setup page.
Explore the Admin Interface
The Admin interface is where you will spend most of your time configuring authentik. It is separate from the user-facing interface you just landed on.
- Click the Admin Interface button in the top navigation bar.
You can also navigate directly to http://localhost:9000/if/admin/.
Take a minute to orient yourself with the left sidebar. The sections you will use throughout this project are:
- Directory contains Users and Groups. This is where you manage identities.
- Applications contains Applications and Providers. An application represents a service (like Grafana) and a provider defines how authentication works (like OAuth2/OIDC).
- Flows & Stages defines the authentication workflows. Notice the default flows that authentik ships with: authentication, authorization, and invalidation (logout).
What Are Flows in authentik?
Flows are multi-step workflows that define how a user moves through authentication, enrollment, or recovery. Each flow is made up of stages (individual actions like entering a password or accepting consent). The default flows handle common scenarios out of the box, so you do not need to build them from scratch.
You now have a running Identity Provider with an admin account and a solid understanding of where everything lives. Next up, you will create the OAuth2/OIDC provider and application that will let Grafana delegate authentication to authentik.
Create an OAuth2/OIDC Provider and Application for Grafana
Your authentik instance is running and you have access to the Admin interface. Before Grafana can delegate authentication to authentik, authentik needs to know about Grafana. In authentik's model, every service that relies on authentik for login is represented by two objects: an Application (the thing users see and access) and a Provider (the protocol configuration that handles the actual authentication exchange). In this step, you will create both and collect the credentials Grafana needs.
In This Step, Get Ready To:
- Create a Grafana application and OAuth2/OIDC provider pair in authentik.
- Retrieve the Client ID and Client Secret that Grafana will use to communicate with authentik.
Create the Application and Provider Pair
authentik lets you create an application and its provider together in a single wizard. The application defines what users see (the name, icon, and launch URL). The provider defines the protocol details: which OAuth2 endpoints to expose, which redirect URIs to allow, and which signing key to use for tokens.
- In the Admin interface, navigate to Applications > Applications in the left sidebar.
- Click Create with Provider.
The wizard opens with the Application configuration first.
- Set the Name to Grafana.
- Leave Policy engine mode set to Any.
- Select OAuth2/OpenID Connect as the Provider type.
The wizard advances to the Provider configuration. This is where you define how the OpenID Connect handshake will work.
- Set Authorization flow to the default implicit authorization flow.
- Under Redirect URIs/Origins (RegEx), add a Strict redirect URI set to http://localhost:3000/login/generic_oauth.
- Set Logout Method to Front-channel.
- Set Signing key to authentik Self-signed Certificate.
- Click Submit.
Why Front-channel Logout?
Back-channel logout requires the application to expose an endpoint that the IdP calls directly. Most applications, including Grafana, do not support this. Front-channel logout works by redirecting the user's browser to each application's logout URL, which is universally supported.
What is the Redirect URI For?
The redirect URI tells authentik where to send the user after a successful login. Grafana's Generic OAuth handler listens at /login/generic_oauth. authentik will refuse to redirect to any URL not on this list, which prevents authorization code interception attacks.
Note the Client ID, Client Secret, and Slug
Grafana needs three pieces of information from authentik to complete the OAuth2 handshake: the Client ID, the Client Secret, and the application slug (used in the logout URL). You will plug these values into Grafana's configuration in the next step.
- Navigate to Applications > Providers in the left sidebar.
- Click on the Grafana provider you just created.
- Copy the Client ID and Client Secret values and save them somewhere accessible.
- Note the application slug. It is typically grafana, derived from the application name you entered.
Pro tip: where the slug appears
The slug is used in only one URL: the end-session (logout) endpoint at /application/o/grafana/end-session/. All other OAuth2 endpoints (authorize, token, userinfo) are global and do not include the slug.
You now have everything authentik needs to recognize Grafana as a trusted relying party. Next up, you will deploy Grafana and feed it these credentials so it can redirect users to authentik for login.
Deploy Grafana and Wire It to authentik
You have a fully configured OAuth2/OIDC provider in authentik waiting for a client to connect. Now you need to deploy Grafana and point it at authentik's OAuth2 endpoints so users can authenticate through your Identity Provider. The key challenge here is getting the networking right. Some URLs are hit by your browser (on the host machine), while others are server-to-server calls between Docker containers.
In This Step, Get Ready To:
- Create a Docker Compose override file that adds Grafana to your authentik stack.
- Configure Grafana's Generic OAuth environment variables to point at authentik's OIDC endpoints.
- Verify the Grafana login page shows a "Sign in with authentik" button.
Create a Grafana Compose Override File
Docker Compose automatically merges a file named compose.override.yml with your main compose.yml when you run docker compose up. This lets you add Grafana to the stack without modifying authentik's official compose file.
- In your project directory (the same folder as compose.yml), create a new file called compose.override.yml.
- Paste the following content, replacing the Client ID and Client Secret with the values you copied in the previous step.
services:
grafana:
image: grafana/grafana
ports:
- "3000:3000"
environment:
# Enable Generic OAuth and name the button
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
GF_AUTH_GENERIC_OAUTH_NAME: "authentik"
# Client credentials from your authentik provider
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: "your-client-id-here"
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: "your-client-secret-here"
# Request these OIDC scopes
GF_AUTH_GENERIC_OAUTH_SCOPES: "openid profile email"
# Browser-facing URL (host machine hits localhost)
GF_AUTH_GENERIC_OAUTH_AUTH_URL: "http://localhost:9000/application/o/authorize/"
# Server-to-server URLs (Grafana container talks to authentik container)
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: "http://server:9000/application/o/token/"
GF_AUTH_GENERIC_OAUTH_API_URL: "http://server:9000/application/o/userinfo/"
# Redirect after logout
GF_AUTH_SIGNOUT_REDIRECT_URL: "http://localhost:9000/application/o/grafana/end-session/"
# Grafana's own root URL
GF_SERVER_ROOT_URL: "http://localhost:3000"
networks:
- default
Why Are Some URLs localhost and Others Are Not?
The auth_url is a browser redirect. Your browser runs on the host machine, so it needs localhost:9000 to reach authentik.
The token_url and api_url are server-to-server calls. The Grafana container makes these requests directly to the authentik container over the Docker network. If you used localhost here, the Grafana container would try to talk to itself, and the token exchange would fail.
What Service Name Should I Use for the Token and API URLs?
The official authentik compose.yml names the authentik server service server. Open your downloaded compose.yml and look for the service name under the authentik server definition. Use that name in your token and API URLs. If it says server:, then http://server:9000/... is correct.
If the token exchange still fails, help me debug my Grafana-to-authentik token URL networking issue.
Start Grafana and Verify It Is Running
- Run docker compose up -d to start the updated stack.
docker compose up -d
Docker Compose detects the override file automatically and merges it with your main compose file. The authentik containers stay running, and a new Grafana container starts alongside them.
- Verify all containers are running with docker compose ps.
docker compose ps
What Should I See?
You should see five containers running: the authentik server, worker, PostgreSQL, Redis, and now Grafana. All should show a status of Up or running.
- Open http://localhost:3000 in your browser.
- Confirm the Grafana login page loads and you see a Sign in with authentik button below the standard login form.
Don't See the "Sign in with authentik" Button?
If the Grafana login page loads but there is no OAuth button, the GF_AUTH_GENERIC_OAUTH_ENABLED environment variable is not being picked up. Double-check that your compose.override.yml is in the same directory as compose.yml and that the YAML indentation is correct.
Try running docker compose config to see the merged configuration. If the Grafana service does not appear, the override file is not being loaded. Help me troubleshoot my compose override file.
Grafana is deployed and wired to authentik's OAuth2 endpoints. Next up, you'll create a test user in authentik and prove the full SSO login redirect flow works end to end.
Create Users, Groups, and Test the SSO Flow
Your authentik instance is running and Grafana is wired up to delegate authentication through OAuth2/OIDC. The infrastructure is in place, but you haven't proven it actually works yet. In this step, you'll create a test user, walk through the full SSO redirect flow, and verify the authentication event in authentik's audit log.
In This Step, Get Ready To:
- Create a non-admin test user in authentik.
- Log into Grafana through authentik's SSO redirect flow.
- Verify the authentication event in authentik's event log.
Create a Test User in authentik
The akadmin account is your superuser. To test the SSO flow realistically, you need a regular user account that has no admin privileges in authentik itself.
- In the authentik Admin interface, navigate to Directory > Users.
- Click Create User.
- Fill in a Name, Username, and Email for your test user.
- Make sure Is active is checked, then click Create.
- Click on the newly created user to open their detail page.
- Click Set Password and assign a password you'll remember for testing.
Pro tip: use a simple test password
This is a local-only environment with no external exposure. A simple password like testpass123 is fine for your test user. Save the complexity for production.
Test the SSO Login Flow
This is the moment of truth. You'll walk through the full OAuth2 authorization code flow from the user's perspective: starting at Grafana, redirecting to authentik for authentication, and landing back in Grafana with a valid session.
- Open http://localhost:3000 in a new incognito or private browser window.
- Click Sign in with authentik on the Grafana login page.
Your browser redirects to authentik's login page at localhost:9000. This is the authorization endpoint doing its job.
- Enter your test user's username and password.
- Click Log in.
After successful authentication, authentik redirects you back to Grafana at localhost:3000. You should now be logged in as your test user.
- Verify your identity by clicking the user avatar in the bottom-left corner of the Grafana interface.
- Confirm the displayed name and email match the test user you created in authentik.
What just happened under the hood?
When you clicked Sign in with authentik, Grafana redirected your browser to authentik's /application/o/authorize/ endpoint with its Client ID and requested scopes. After you authenticated, authentik issued an authorization code and redirected back to Grafana's /login/generic_oauth callback. Grafana then exchanged that code for an access token via a server-to-server call to authentik's token endpoint. Finally, Grafana used the token to fetch your user info and create a local session.
Seeing a login error or redirect failure?
The most common cause is a mismatch between the redirect URI configured in authentik and Grafana's actual callback URL. Double-check that the Strict redirect URI in your authentik provider is exactly http://localhost:3000/login/generic_oauth. Also verify that the token and API URLs in your compose override use the Docker internal hostname (e.g., authentik-server:9000), not localhost. Inside the Grafana container, localhost refers to the Grafana container itself, not your host machine.
Still stuck? Help me debug my SSO redirect failure.
Verify the Login in authentik's Event Log
A working login is only half the picture. As an IdP administrator, you also need to confirm that authentik recorded the authentication event. This audit trail is critical for security monitoring in any identity system.
- In the authentik Admin interface, navigate to Events > Logs.
- Look for an authorization event showing your test user authenticating to the Grafana application.
- Click on the event to inspect the details, including the user, application, and timestamp.
This event confirms that the full OAuth2 authorization code flow completed successfully. authentik issued the authorization code, exchanged it for a token, and served the user info to Grafana.
What should I see?
You should see an event with the action type related to authorization. The event details will show the test user's username, the Grafana application name, and the timestamp of the login. If you tested multiple times, you'll see multiple events.
You've just proven the entire SSO integration end to end. Next up, the Secret Mission takes this further by mapping authentik groups to Grafana roles, giving you automatic RBAC through OIDC claims.
Secret mission
Map authentik Groups to Grafana Roles
Your SSO login works, but every user gets the same default role in Grafana. In a real environment, you need group membership to automatically control who gets Admin, Editor, or Viewer access. Can you wire up authentik groups to Grafana RBAC using OIDC claims?
Before you go
Clean Up Your Resources
This project runs entirely on local Docker containers, so there are no cloud resources or ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- authentik server container.
- authentik worker container.
- PostgreSQL container (authentik database).
- Redis container (authentik cache).
- Grafana container.
- Docker volumes for PostgreSQL and Redis data.
- Project directory with compose.yml, compose.override.yml, and .env files.
Keep everything running
No action needed. Choose this if you are still actively experimenting with authentik integrations, policies, or flows.
- All containers will continue running and remain accessible at localhost:9000 (authentik) and localhost:3000 (Grafana).
- The containers will use approximately 2 GB of RAM while running.
Pause - I'll come back to this later
Shut down running containers to free up memory while keeping all your data intact. Resume later with a single command.
- Navigate to your project directory (e.g., ~/authentik-project).
- Run docker compose stop to stop all containers without removing any data.
- When you are ready to resume, run docker compose start from the same directory.
Delete - I don't want to use this again
Remove all project containers, volumes, and data permanently. This deletes all authentik configuration, users, groups, and Grafana data.
- Navigate to your project directory (e.g., ~/authentik-project).
- Run docker compose down -v to stop all containers and remove all volumes.
- Delete the project directory with rm -rf ~/authentik-project to remove the compose files and .env secrets.
- Optionally, run docker image prune -a to reclaim disk space from the downloaded images.
Mission accomplished
That's a Wrap!
Nice work! You just deployed a self-hosted Identity Provider from scratch and wired it up for real Single Sign-On.
Here's what you accomplished:
- Deployed a full authentik stack (server, worker, PostgreSQL, Redis) using Docker Compose and configured it as a functioning Identity Provider.
- Created an OAuth2/OIDC provider and application in authentik, then integrated Grafana to authenticate through it with a working SSO redirect flow.
- Created users and groups in authentik, tested end-to-end login, and verified authentication events in the audit log.
- Configured group-to-role mapping so authentik groups automatically control Grafana Admin, Editor, and Viewer roles via OIDC claims and JMESPath expressions.
Ready to quiz yourself?