Setting Up Traefik Proxy on k3s with Forward Auth using Authorization Header Part 2

In Part 1, we covered the basics of setting up Traefik proxy on k3s and configuring forward authentication. Now, in part 2, we will deploy a sample application to Kubernetes and set up the callback URL on a Node.js Express app to handle the authentication response from GitHub.

Step 4: Configure Traefik

We will now configure Traefik to use our Node.js Express app as the authentication provider for our web application.

  1. Create a new Kubernetes Secret with the GitHub OAuth credentials:
kubectl create secret generic myapp-oauth \
  --from-literal=client_id=<your-github-client-id> \

Replace <your-github-client-id> and <your-github-client-secret> with the actual values you obtained in step 2.

  1. Create a new Kubernetes ConfigMap with the Traefik configuration:
kubectl create configmap traefik-config \

In this case, traefik.toml is a file containing the Traefik configuration. Here’s an example configuration:

# traefik.toml
  address = "http://myapp.mynamespace.svc.cluster.local:3000/auth/github"
  authResponseHeaders = ["Authorization"]

  Authorization = "Bearer ${http:middleware:myapp-auth.forwardauth}"

  rule = "Host(``)"
  entryPoints = ["websecure"]
  middlewares = ["myapp-auth"]
  service = "myapp-service"

    passHostHeader = true
    servers = [
      { url = "http://myapp.mynamespace.svc.cluster.local" }

In this configuration, we have defined a middleware called myapp-auth that uses the forwardauth plugin to forward authentication requests to our Node.js Express app. The authResponseHeaders option tells Traefik to include the Authorization header in the authentication response.

We have also defined a custom request header called Authorization that includes the access token returned by our Node.js Express app. This header will be added to all requests to the myapp service.

Finally, we have defined a router called myapp that listens for requests to the hostname and uses the myapp-auth middleware. The router forwards requests to a Kubernetes service called myapp-service.

Note that you should replace myapp with the actual name of your application.

Once you have created the secret and the configmap, you can deploy Traefik to your Kubernetes cluster:

kubectl apply -f traefik.yaml

Replace traefik.yaml with the actual name of your Traefik deployment file.

Step 5: Deploy the Application

We are now ready to deploy our application to Kubernetes. Here’s how:

  1. Create a new file called deployment.yaml with the following contents:
apiVersion: apps/v1
kind: Deployment
  name: myapp
    app: myapp
  replicas: 1
      app: myapp
        app: myapp
      - name: myapp
        image: myapp:latest
        - containerPort: 3000
        - name: NODE_ENV
          value: production
        - name: PORT
          value: "3000"
        - name: CLIENT_ID
  1. Deploy the application to Kubernetes:
kubectl apply -f deployment.yaml
  1. Create a new Kubernetes Service for the application:
kubectl expose deployment myapp --port=80 --target-port=3000 --type=ClusterIP
  1. Create a new Kubernetes Ingress for the application:
kind: Ingress
  name: myapp
  annotations: traefik letsencrypt-prod
  - hosts:
    secretName: myapp-tls
  - host:
      - path: /
        pathType: Prefix
            name: myapp
              name: http

In this Ingress configuration, we are using the traefik ingress class to route traffic to our application. We are also using the letsencrypt-prod cluster issuer to automatically obtain a TLS certificate from Let’s Encrypt.

Replace with the actual hostname of your application.

Once you have deployed your application, you should be able to access it by visiting in your web browser.

Step 6: Implement the Callback URL on Node.js Express

Finally, we need to implement the callback URL on our Node.js Express app to handle the authentication response from GitHub.

  1. Install the passport-github2 and jsonwebtoken packages:
npm install passport-github2 jsonwebtoken
  1. Create a new file called auth.js with the following contents:
const passport = require('passport');
const { Strategy: GitHubStrategy } = require('passport-github2');
const jwt = require('jsonwebtoken');

const clientID = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
const jwtSecret = process.env.JWT_SECRET;

passport.use(new GitHubStrategy({
  callbackURL: '/auth/github/callback'
}, (accessToken, refreshToken, profile, done) => {
  const jwtPayload = {
    username: profile.username
  const jwtToken = jwt.sign(jwtPayload, jwtSecret, { expiresIn: '1h' });
  return done(null, { jwtToken });

module.exports = passport;

In this file, we are using the passport-github2 package to handle the authentication with GitHub. We are also using the jsonwebtoken package to create a JWT token with the user’s ID and username.

Replace jwtSecret with a secret key for signing the JWT token.

  1. Create a new file called index.js with the following contents:
const express = require('express');
const session = require('express-session');
const auth = require('./auth');

const app = express();
const port = process.env.PORT || 3000;

  secret: 'my-secret',
  resave: false,
  saveUninitialized: false


app.get('/', (req, res) => {
  res.send('Hello World!');

app.get('/auth/github', auth.authenticate('github'));

app.get('/auth/github/callback', auth.authenticate('github', { failureRedirect: '/login' }), (req, res) => {

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);

In this file, we are using the express package to create an HTTP server. We are also using the express-session package to handle sessions.

We are initializing passport using the auth module that we created in auth.js. We are also using the session middleware to enable session support.

We have defined three routes:

  • /: This is the default route that displays a “Hello World!” message.
  • /auth/github: This route redirects the user to GitHub for authentication.
  • /auth/github/callback: This route handles the authentication response from GitHub.

When the user visits the /auth/github route, they will be redirected to the GitHub authentication page. After the user has authenticated with GitHub, they will be redirected to the /auth/github/callback route.

In the callback route, we are using the auth.authenticate middleware to handle the authentication response from GitHub. If the authentication is successful, we will redirect the user to the default route.

  1. Start the Node.js Express app:
npm start

You should now be able to visit http://localhost:3000 in your web browser and see the “Hello World!” message. When you visit http://localhost:3000/auth/github, you should be redirected to GitHub for authentication. After you have authenticated with GitHub, you should be redirected back to http://localhost:3000 and see the “Hello World!” message again.

Congratulations! You have successfully set up Traefik proxy on k3s with forward auth using the Authorization header, deployed a sample application to Kubernetes, and implemented the callback URL on a Node.js Express app to handle the authentication response from GitHub.


Traefik proxy is a powerful tool for managing and routing traffic in a Kubernetes cluster. By setting up forward authentication with the Authorization header, you can add an extra layer of security to your applications and ensure that only authorized users can access them.

In this tutorial, we covered the following:

  • Setting up Traefik proxy on k3s
  • Configuring forward authentication with the Authorization header
  • Deploying a sample application to Kubernetes
  • Implementing the callback URL on a Node.js Express app to handle the authentication response from GitHub

I hope this tutorial has been helpful in getting you started with Traefik proxy and forward authentication. Happy coding!





  • Let’s Explore!

    It’s 04:03am Tuesday, and I’m starting this blog. There are a lot of things currently bothering my mind, and sometimes I’m thinking of what the future will look like. Waiting till 10:00 to get onto my work and start doing some stuff. Let’s find some beautiful place and get lost. – Me I’ve been a… Read More

  • Installing MySQL2 Ruby Gem in macOS Mojave

    Installing MySQL2 gem became a common problem for people who uses macOS to develop Ruby1 based apps that utilized MySQL2 data store. I’ve personally encountered this problem myself back in the days and still encountering this on brand new setup macOS workstation. In this article, we will go through the steps I did to resolved… Read More

  • Changing Xserver Default Applications Using XDG Tools

    XDG ( which stands for X Desktop Group is a group which develop the X11 and xdg utilities which currently runs as barebones of linux desktop. So how do we change the defaults when opening a file on XServer? Be free, and live life fully. — Caroline Shaw. So how do we configure XDG? Tools… Read More