Traefik Forward Auth Guide – Simple, Secure Google SSO [2022]

Want to protect your Docker stack with something stronger than basic HTTP authentication? Google OAuth2 SSO with Traefik Forward Auth is strong contender.

Note: An updated version of this guide is available: Google OAuth Traefik Forward Auth [2024]: Most Convenient MFA

Tired of all your docker services having their authentication system? For those that don't, do you hate Traefik's basic auth? Then, read on to setup up Google OAuth2 with Traefik Forward Auth. Enjoy the convenience of secure single-sign-on for your Docker services.

I was so excited to find that thomseddon’s image, Traefik Forward Auth, could secure my Docker services. This image provides a lightweight forward authentication using Traefik Google OAuth2.

Why Traefik Google OAuth2 for Docker Services?

Google OAuth2 enables you to use your Google account to sign in to your services. Using Google OAuth with Traefik will allow you to whitelist accounts, implement Google’s 2FA, as well as provide a Single Sign-On (SSO) to your services. This not only offers the convenience of not having to sign in frequently but also improves security.

For this reason, on my smart home setup, which uses several docker services, I recently enabled Google OAuth SSO for many of the services.

If you're already running Docker based Media Server behind a Traefik reverse proxy, then this is a logical next step. [Read: Podman vs Docker: 6 Reasons why I am HAPPY I switched]

Adding Traefik OAuth2 for your Docker services will be an easy step and important addition to your Docker Traefik stack.

Which authentication system do you prefer or use for your Docker stack?

View Results

Loading ... Loading ...

This guide was originally written for Traefik v1.7.16 and then for Traefik v2.2. A lot has changed since then, both in Traefik as well as my setup shared in my GitHub Repo. This guide will based on Traefik 2.7, which is the current version at the time of publishing this guide.

Configure Traefik Forward Auth with Google OAuth2

Note: An updated version of this guide is available: Google OAuth Traefik Forward Auth [2024]: Most Convenient MFA

Adding the basic authentication that Traefik provides is the simplest way to protect your docker and non-docker services.

In our previous guide we walked through how to use .htpasswd login credentials and Traefik auth middleware for adding basic authentication using labels.

For a single service, this can be useful, but I found it quickly became inconvenient and tedious once I had to sign-in to multiple services and for every browser session.

After implementing Traefik forward authentication, I now only need to sign-in once, and by implementing Traefik OAuth2 with Google I can add 2-factor authentication (2FA), making this method much more secure and convenient than using basic auth.

If you prefer a private self-hosted (rather than relying on Google) multi-factor authentication system, then look into Authelia. I use Authelia for my multi-author WordPress website and Traefik OAuth2 for my private homelab.

What is OAuth?

OAuth is an open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords. This mechanism is used by companies such as Amazon, Google, Facebook, Microsoft, and Twitter to permit users to share information about their accounts with third-party applications or websites.” - Wikipedia

Before configuring Traefik Forward Auth with Google OAuth2, let us see how it all fits together.

How does Google OAuth2 with Traefik work?

Google OAuth login and authentication for Traefik acts like a gatekeeper for your services, allowing or denying access after checking for an authorized cookie in your browser. To sum it up, the process goes something like this:

  1. A request is made for our Host ( e.g.: https://traefik.example.com)
  2. The request is routed by our DNS provider to our WAN IP, where ports 80 and 443 are forwarded to the Traefik container.
  3. Traefik sees the incoming request and recognizes that Forward Auth is defined in the labels for that Host, therefore the request is forwarded to the Traefik Forward Auth container.
  4. The container then checks to see if the browser already has an authorized cookie. If there's no cookie, the request is sent to Google's OAuth2 Authorization Server.
  5. After successfully logging in to Google, the request is sent to the redirect URI identified for the Web Application (https://oauth.example.com/_oauth).
  6. An authorized cookie is then saved in the browser, and the user is sent to the backend service.

The next time that this browser tries to access a service protected by OAuth-based login and authentication, the cookie will be recognized and the user will be taken to their service, without being prompted to sign in!

Traefik Forward Auth With Google Oauth - Process Flow
Traefik Forward Auth With Google Oauth - Process Flow

This process happens very quickly, and once your browser receives the cookie you'll forget you've even enabled Google OAuth with Traefik!

Note: The Traefik Forward Auth image uses OpenID Connect (OIDC), which is an authentication layer on top of the OAuth 2.0 protocol. The docker image presented in this guide supports Google and also other OIDC providers.

With the basics taken care of let's move on to setting Google OAuth Traefik forward authentication for our Docker services.

How do I setup OAuth?

Setting up Google OAuth for Docker using Traefik, involves 3 steps: 1) creating DNS records, 2) configuring Google OAuth2 Service, and 2) modifying Docker compose files and adding the Traefik labels to activate forward authentication.

So, first, we'll need to configure the Traefik OAuth2 service. Let's set up all of the prerequisites now:

Step 1: Create DNS Records

Start by creating a new CNAME DNS record for our OAuth service (Google will redirect to this address after authentication). For clarity, throughout this guide we'll use the domain name example.com.

Set the DNS record as oauth.example.com. The pictures below show a screenshot from Cloudflare. Depending on your DNS provider, things may look different for you but essentially have the same content.

Create Dns Records For Google Oauth2
Create Dns Records For Google Oauth2

Note that DNS records can take several hours to propagate and become active.

Alternatively, if you have enabled a wildcard CNAME record pointing to your root domain, then you may skip this step.

Step 2: Configure Google OAuth2 Service

With the DNS records created, let us move on the configuring Google OAuth.

Step 2a: Create a Google Project

We need to create a Google Project that will contain our Web App, Consent Screen, and Credentials. This process is very similar to what is described in our guide on setting up Google Assistant for Home Assistant.

Navigate to the Google Cloud Developers Console and make sure that you are signed into the correct Google account that you want to use (This will normally be your e-mail address).

Note: Sign out of other active Google accounts to make sure that the correct account is used at each step.

If prompted, you'll need to agree to the Google Cloud Platform Terms of Service to use their API:

Google Terms Of Service
Google Terms Of Service

It's free to use Google's OAuth service, so we can Dismiss the free trial for now. Click on Select a project and New project.

Create A New Project For Oauth
Create A New Project For Oauth

Enter a unique name to identify the project, such as “Traefik Authentication”. Click Create.

Google Oauth New Project Details
Google Oauth New Project Details

Step 2b: Create OAuth Credentials

Now that our project has been created, we need to create a client ID and client secret in order to authenticate with Google. Choose our Traefik Authentication project, and under the Navigation menu select APIs & Services > Credentials. Click on Create Credentials > OAuth client ID.

Navigate To Create Oauth Client Id
Navigate To Create Oauth Client Id

Step 2c: Configure the Consent Screen

Once you click OAuth Client ID, you will see the note to configure the consent screen as shown below. A configuring a consent screen is required before proceeding.

Configure Consent Screen For Google Oauth2
Configure Consent Screen For Google Oauth2

If you're not automatically prompted, select the OAuth consent screen from the left panel.

Choose a name for your app, such as "Traefik Auth", then under the Authorized domains section enter your domain, for instance, “example.com”. Make sure that you press Enter to add it, and then click Save.

Create Oauth Consent Screen
Create Oauth Consent Screen

After hitting Save, you will return to creating an OAuth Client ID.

Step 2d: Create the OAuth client ID

Now select the Web Application type and enter a name for your web application, such as “Traefik”. In addition, you'll need to enter your Authorized redirect URI as https://oauth.example.com/_oauth. Make sure that you press Enter to add it, and then click Save.

Note: You are only allowed to add redirect URIs that direct to your Authorized Domains. Return to the OAuth consent screen if you need to edit them.

Creating Oauth Client Id
Creating Oauth Client Id

The credentials for our SSO for Docker have been created! Copy and save the client ID and client secret; we'll need to use them in the next step.

Google Oauth Client Credentials
Google Oauth Client Credentials

Step 3: Setup Traefik Forward Authentication with OAuth2

Note: An updated version of this guide is available: Google OAuth Traefik Forward Auth [2024]: Most Convenient MFA

Now that the OAuth credentials have been configured, the last thing to do is set up the OAuth container. Sign-in to your local machine, or use one of the several awesome SSH clients to sign in remotely.

Make sure to stop Traefik (if necessary), and edit your docker-compose file to add the Traefik labels and OAuth container, as described below.

Be the 1 in 200,000. Help us sustain what we do.
113 / 150 by Dec 31, 2024
Join Us (starting from just $1.67/month)

The assumption is that you have already read and followed most of my Traefik 2 guide and are reading this post just to implement Google OAuth. [Read: 20 Docker Security Best Practices – Hardening Traefik Docker Stack]

Step 3a: Create Traefik Auth Middleware and Chain

After publishing my first two Traefik OAuth guides (for v1.7 and v2.2), I moved from TOML to YML for my Traefik dynamic configurations. Therefore, in previous versions of this guide you will find TOML examples. In this guide, we will use YML exclusively to align with my other recent guides and my GitHub repo.

Let us now specify a Traefik auth middleware for OAuth2. Open middlewares.yml file that was created in my Traefik guide and add the following lines below what is already present:

    middlewares-oauth:
      forwardAuth:
        address: "http://oauth:4181" # Make sure you have the OAuth service in docker-compose.yml
        trustForwardHeader: true
        authResponseHeaders:
          - "X-Forwarded-User"

In addition, let us create a new middleware chain for services that will use Google OAuth. Open middleware-chains.yml that was created in my Traefik guide and add the following lines below what is already present:

    chain-oauth:
      chain:
        middlewares:
          - middlewares-rate-limit
          - middlewares-https-redirectscheme
          - middlewares-secure-headers
          - middlewares-oauth
          - middlewares-compress
Note:

  1. Middlewares for rate limit, HTTPS redirection, security headers, and compression must be defined following my Traefik guide. Otherwise, Traefik won't start.
  2. In my GitHub Repo you may find more middlewares than what is described above. For OAuth2 purposes, the above middlewares are sufficient. As you follow more of my guides you may add additional middlewares.

Save the files and exit editing.

Step 3b: Add Traefik Forward Auth Secrets

In my first version of this guide published in 2019, I used environmental variables to provide the required Google developer console credentials. In 2020, I moved to Docker secrets. In this version, we will use Docker secrets as well but in a slightly different way.

Instead of creating multiple secrets, we are going to create one single secret file for Traefik forward auth that contains all the credentials.

Create a file called traefik_forward_auth inside the secrets folder (DOCKER-ROOT-FOLER\secrets if your setup is based on my guides) and add the following content to it:

providers.google.client-id=yourGOOGLEclientID
providers.google.client-secret=yourCLIENTsecret
secret=yourOAUTHsecret
whitelist=yourEMAILaddress1
whitelist=yourEMAILaddress2

Customize the above using the information below:

  • yourGOOGLEclientID and yourCLIENTsecret: Obtained previously in this Traefik Oauth2 guide.
  • yourOAUTHsecret: This is used to sign the cookie and should be random. Generate a random secret with:
    openssl rand -hex 16
    

    Alternatively, you may use an online service like this one, to generate your random secret.

    08 Random Oauth Secret | Smarthomebeginner
    Random Oauth Secret
  • yourEMAILaddress1: Google email ID which will be used to authenticate. Optionally, you may add additional email addresses that are allowed to authenticate (e.g. yourEMAILaddress2; remove this line if you only want to allow one email ID).

Save and exit.

Note that the secrets folder and the traefik_forward_auth file should have a permission of 600 and owned by root user.

Next, let us setup the OAuth Forwarder container.

Step 3c: Add OAuth Forwarder Container

Open your docker-compose file (docker-compose-t2.yml) that was created based on our previous Traefik 2 tutorial and add the following to it.

If you did not follow my previous guide, then make sure that the required Docker extension fields are defined properly.

Note: In my GitHub repo (which should be your main source of reference for docker-compose examples as it has the most up-to-date information), I use several domain names: DOMAINNAME_HOME_SYNOLOGY (for my Docker Home Server on Synology), DOMAINNAME_CLOUD_SERVER (for my Dedicated Server in a Datacenter, with Proxmox), DOMAINNAME_SHB (domain name for this website), and DOMAINNAME_KHUB (domain name of another non-WordPress website I host). You may find any of these domain variables in my examples. Make sure to substitute this variable with your own.
  # Google OAuth - Single Sign On using OAuth 2.0
  oauth:
    <<: *common-keys-core # See EXTENSION FIELDS at the top
    container_name: oauth
    image: thomseddon/traefik-forward-auth:latest
    # image: thomseddon/traefik-forward-auth:2.1-arm # Use this image with Raspberry Pi
    environment:
      - CONFIG=/config
      - COOKIE_DOMAIN=$DOMAINNAME_CLOUD_SERVER
      - INSECURE_COOKIE=false
      - AUTH_HOST=oauth.$DOMAINNAME_CLOUD_SERVER
      - URL_PATH=/_oauth
      - LOG_LEVEL=info
      - LOG_FORMAT=text
      - LIFETIME=86400 # 1 day
      - DEFAULT_ACTION=auth
      - DEFAULT_PROVIDER=google
    secrets:
      - source: traefik_forward_auth
        target: /config
    labels:
      - "traefik.enable=true"
      ## HTTP Routers
      - "traefik.http.routers.oauth-rtr.tls=true"
      - "traefik.http.routers.oauth-rtr.entrypoints=https"
      - "traefik.http.routers.oauth-rtr.rule=Host(`oauth.$DOMAINNAME_CLOUD_SERVER`)"
      ## Middlewares
      - "traefik.http.routers.oauth-rtr.middlewares=chain-oauth@file"
      ## HTTP Services
      - "traefik.http.routers.oauth-rtr.service=oauth-svc"
      - "traefik.http.services.oauth-svc.loadbalancer.server.port=4181"

The docker extension common-keys-core will add the network t2_proxy, restart policy (always), and other security options, as defined in the Traefik 2 guide.

Notice that we are using the Traefik auth middleware chain (chain-oauth) here for authentication instead of basic auth. Use the correct image for your system's architecture. For example, Raspberry Pi has a different image tag.

You may also change the duration (LIFETIME) for which the authentication is valid from 1 day specified in seconds to another duration. Initially, set the LOG_LEVEL to trace or debug. Once everything works, you may change it to warn.

Optionally, the rest of the environment variables defined for the oauth can be configured to your liking (if you know what you are doing).

Once done, use the docker-compose up command or the shortcut dcup2 if you have bash_aliases setup based on my GitHub repo. You should now be redirected to Google OAuth login page before reaching the service.

Google Oauth Login For Docker Services
Google Oauth Login For Docker Services

Step 3d: Adding Google OAuth for Docker Services

Let's take the example of Traefik 2 Dashboard. If you followed my Traefik guide, you should now have basic auth using the middleware:

      ## Middlewares
      - "traefik.http.routers.traefik-rtr.middlewares=middlewares-basic-auth@file" 

Or, the middleware chain:

      - "traefik.http.routers.traefik-rtr.middlewares=chain-basic-auth@file" 

We already defined a middleware chain for Traefik oauth (chain-oauth) above.

Changing from basic auth to oauth is now as simple as changing chain-basic-auth to chain-oauth in the docker-compose file (shown below).

      - "traefik.http.routers.traefik-rtr.middlewares=chain-oauth@file" 

So there you go, OAuth-based login and authentication for the Traefik reverse proxy stack.

Once done, use the docker-compose up command (or the shortcut dcup2 if you have bash_aliases setup based on my GitHub repo.

Step 3e: Adding OAuth to Other (Non-Docker) Services

Non-docker apps could be any service that is on the host system or on a remote system (e.g. Webmin, Synthing, Pi-Hole, etc. installed on the Docker host or remote system).

Traefik’s File provider allows us to add dynamic routers, middlewares, and services. Earlier we only used our rules directory to add middlewares, but we can easily add an external host by adding a new file to this directory. Traefik will auto-detect and update its configurations.

Let us take the same example of Pi-Hole discussed in my Traefik guide (app-pihole.yml). Pi-Hole is running on a different host (192.168.1.26). In the Traefik guide, we put Pi-Hole behind basic authentication.

To change it to use Traefik OAuth2 authentication, you only have to change chain-basic-auth to chain-oauth in the middlewares section of the router, as shown below.

http:
  routers:
    pihole-rtr:
      rule: "Host(`pihole.{{env "DOMAINNAME_CLOUD_SERVER"}}`)" 
      entryPoints:
        - https
      middlewares:
        - chain-oauth
        - pihole-add-admin
      service: pihole-svc
      tls:
        certResolver: dns-cloudflare
  middlewares:
    pihole-add-admin:
      addPrefix: 
        prefix: "/admin"
  services:
    pihole-svc:
      loadBalancer:
        servers:
          - url: "http://192.168.1.26:80"  # or whatever your external host's IP:port is 

Pi-Hole frontend will be available at pihole.example.com, with the assumption that the environmental variable DOMAINNAME_CLOUD_SERVER is set to example.com and passed to Traefik container as explained in the Traefik guide.

Since the rules directory is dynamic, simply by adding this file to that directory we have created the route. You should be able to connect to Pi-Hole behind Google OAuth2, without restarting Traefik!

Which authentication system do you prefer or use for your Docker stack?

View Results

Loading ... Loading ...

Bypassing OAuth / Selective Authentication

Note: An updated version of this guide is available: Google OAuth Traefik Forward Auth [2024]: Most Convenient MFA

I use the NZB360 app on Android and LunaSea on iOS for remotely managing SABnzbd, Sonarr, Radarr, etc. When these apps are behind OAuth, I could not use these apps remotely using a fully qualified domain name (e.g. https://sonarr.example.com). These apps have no way to authenticate themselves and pass through OAuth.

This was until I discovered rule-based OAuth bypass as described in Auth Forwarder's GitHub page.

You can bypass authentication based on specific keys in the Headers, regular expressions, host, path, query, and more.

Note: By using an incorrectly specified rule, you can easily disable authentication when you do not intend to. Therefore, I strongly recommend specific and narrow rules for bypassing authentication.

Identifying Bypass Rule

How can we figure out what specific rules to use?

This can be quite tricky. As discussed in the link below, a generic way to bypass authentication would be using the path. For example, NZB360 app requests have /api in the path. You may disable authentication for all those requests.

Resource:: Check this GitHub thread for additional information selective authentication.

But this can loosen the security and I recommend setting specific rules. For example, if the request header contains the SABnzbd API key then bypass authentication.

Then the next question, how did I know to look for SABnzbd API key? This requires some trial and error.

First, ensure SABNzbd is behind OAuth. Then set the OAuth container's log level to trace in the environmental variable:

      LOG_LEVEL: trace

Then check the docker logs for the OAuth container (Basic Docker Commands). This will spit out pretty much everything going on in that container, which can be overwhelming. You can trim this down to your app of interest by piping in the grep sabnzbd command.

sudo docker-compose -f ~/docker/docker-compose-t2.yml logs sabnzbd logs -tf --tail="50" 

Now when I try to open SABnzbd through the app of interest, in my case NZB360, it creates an OAuth log entry like the one below.

Oauth Log Entry For Sabnzbd Access Via Nzb360 App
Oauth Log Entry For Sabnzbd Access Via Nzb360 App

Specifying OAuth Bypass Rule

Notice the the uri in the above log screenshot contains the SABnzbd API key. So you can set the bypass use based on this, as follows:

    command: --rule.sabnzbd.action=allow --rule.sabnzbd.rule="HeadersRegexp(`X-Forwarded-Uri`, `$SABNZBD_API_KEY`)"

Oauth Log For Radarr Access Via Nzb360 App
Oauth Log For Radarr Access Via Nzb360 App

For Radarr, Sonarr, Lidarr, etc, you may use the following rule (should work for NZB360 or similar apps):

    command: --rule.radarr.action=allow --rule.radarr.rule="Headers(`X-Api-Key`, `$RADARR_API_KEY`)"

For the full docker-compose, check my GitHub Repo. All the above codes assume that you followed my previous Traefik guide and the API keys are defined correctly in your .env file. Otherwise, the above rules won't work.

Restart the OAuth container and try to access SABnzbd now via the app and browser. The browser should present the OAuth login and the App should take you to the service directly.

There several more ways to specify rules. Check out OAuth Forwarders to GitHub page for all available options.

Using Custom Headers

Some apps (e.g. LunaSea) allow the addition of custom headers. So when the app tries to reach your Radarr, Sonarr, etc., a custom header can be sent.

Custom Headers In Lunasea App
Custom Headers In Lunasea App

This custom header can then be monitored and if present can be used to trigger a bypass. This is an alternative to looking for API keys. You can set one standard header for all Arr-apps on LunaSea and have the same bypass rule for all of them. This also eliminates guesswork and trial and error explained above.

Alternative Bypass Methods

This is my preferred method for bypassing.

Although OAuth Forwarder allows bypassing, I do not use the above method (hence why all the OAuth bypass rules are commented out in the compose files in my GitHub repo).

Traefik has built-in mechanisms for conditional bypassing. Depending on certain conditions, I can specify a different middleware or a middleware chain. This is explained in detail in my separate guide on Traefik Auth bypass.

Several apps in my GitHub repo have auth bypasses set based on certain conditions.

OAuth and Security Headers

One thing to note about using the Traefik OAuth2 service is your security headers. If the service is behind OAuth and you’re trying to check whether your security headers are applied, you will probably receive a lower rating. This caused me a lot of concern at first, until realizing that the headers I was seeing were not actually for my service, but Google’s.

Security Headers With Google Oauth
Security Headers With Google Oauth

Once redirected after successful authentication, the security headers defined for your service should apply automatically.

FAQs

What is traefik-forward-auth-provider?

Traefik forward auth is as service that integrates with a third-party authentication provider (e.g. Google, Microsoft, Authelia, etc.) to secure your services and web applications.

Is traefik-forward-auth-provider popular?

Yes, Traefik forward auth provider is popular among Traefik and Docker enthusiasts. It makes securing applications with strong authentication system, very easy.

What is the difference between OIDC and OAuth?

OIDC or OpenID Connect (OIDC) is a protocol for authentication. It is a set of specifications based on OAuth 2.0, which adds extra features. In essence, OIDC is the authentical protocol while OAuth is the set of specifications for resource access and sharing.

Are there other (more private) alternatives to Google OAuth?

Yes. Authelia and Keycloak are two I can think of. IMHO, Authelia was much simpler to setup, cmopared to Keycloak. There is also Authentik.

How do I sign out of my services that use Google OAuth2?

If you need to logout, sign out from your google services in any other tab/window and your OAuth for services will be invalidated.

Final Thoughts Traefik Forward Authentication

Implementing Google OAuth2 with Traefik forward authentication has been one of the easiest and most secure ways for me to protect my docker services. By whitelisting accounts and implementing Google’s 2FA, I have confidence that I will be the only one that's able to access those services. In addition, I now have an authentication service that allows me to access many of my services with just one login.

As said previously, if you prefer a self-hosted alternative that is more private then Authelia is a great option. In fact, in a multi-user environment, it might be easier and more secure to use Authelia. Unlike Traefik Forward Auth with Google OAuth2, Authelia is email-agnostic (not everyone has a Google account). This is the reason why I use Authelia to protect my multi-author WordPress blog.

I hope you enjoyed learning about Google OAuth with Traefik for Docker services! If you have any questions feel free to leave a comment below.

Be the 1 in 200,000. Help us sustain what we do.
113 / 150 by Dec 31, 2024
Join Us (starting from just $1.67/month)

Anand

Anand is a self-learned computer enthusiast, hopeless tinkerer (if it ain't broke, fix it), a part-time blogger, and a Scientist during the day. He has been blogging since 2010 on Linux, Ubuntu, Home/Media/File Servers, Smart Home Automation, and related HOW-TOs.

Try Deployarr