Authelia Identity Provider

Created: 6 Jul 2025.

Why I need an Identity Provider

  • After I started hosting this public website on my home server, I realised how useful all the documentation was – not just for me, but for others to refer to, especially when I met someone who wanted to know how something was done.

  • Being a amatuer photography enthusiast, it wasn’t long before I was longing to share my photos on my site as well. But it had to be behind an authenticated site. So I started thinking about how to go about achieving this. The more I searched, the more I realised it wasn’t going to easy.

What led me to Authelia

The initial approach

  • I started out dreaming of the ideal solution, one that would be tailored to what I wanted:

    • cater for multiple realms / domains

    • enforce two factor authentication

    • single ID sign on for the multiple realms / web services I intended to host

  • This resulted in designing a non-trivial complex relational database design to cater to the above requirements.

  • I did dwell into doing a POC with some components of this database design using JPA and Hibernate persistence, but soon realised it would take quite some effort to do the development work.

Then I got a Yubikey

  • I decided to buy a Yubikey out of curiosity more than anything else. I just had an inkling that it would be quite useful. And then I realised why it was so secure; namely that, the private key of a certificate key pair would never leave the Yubikey device. The public key of that pair would be what was kept by the portal you wanted to register this with.

  • I also spent some time looking at Java code, to understand how I could implement it into a simple authentication portal.

  • Which meant that I needed a full stack solution with Angular or React on the front end.

  • While taking a step back and trying to see if there was a simpler solution, it led me to look for ready made identity provider solutions.

The path I settled on

  • Having given up on a custom developed software solution, I eventually narrowed my short listed candidates to Keycloak, Authentik, Authelia and Pocket ID:

    • Keycloak was an enterprise grade solution which was too complex and an overkill.

    • Authelia seemed okay, but initially, it still seemed a little too complex for me.

    • Pocket ID was too simple and didn’t have good documentation or the ability to tweak it.

    • Authentik required you to use docker, which was not in my plan, as I had the option of deploying my chosen solutions on FreeBSD Bastilles or Proxmox containers / VMs.

  • But, I eventually decided to give Authelia a go as it had enough features, maturity and reliability for what I wanted to do, and I could host it in a Proxmox container.

  • I took me a while to understand the configuration options available and how to get it up and working, and integrate it with my NGINX reverse proxy. And the initial POC worked with just single factor authentication with integration to MySQL and OpenLDAP.

  • So, without further ado, let me provide details on how I have setup Authelia and my working configuration file. Of course, I’ve cleared out the sensitive secret entries, but the rest is exactly as I have configured it on my Authelia container.

Authentication Flow

The diagram below shows the typical flow for an incoming web request coming from the internet.

../../_images/NGINX-Authelia-Integration.png
  • Start (01): Any incoming web request comes through TCP port 80 (HTTP) and TCP port 443. The pfSense router uses Network Address Translation (NAT) to send this request to the NGINX reverse web proxy (192.168.1.10). As a side note, Let’s Encrypt is used to provide the HTTPS certificate for the web proxy, and it requires that both these ports be open for certificate renewal.

  • 02, 03 & 04: The reverse proxy checks if the requested internal web site requires authentication or not and forwards the request on as needed.

    • If the site is meant to be public without any authentication (No), the reverse proxy forwards the request to the destination container **(04a). In the example above, if the request is for the public website, the request is forwarded to 192.168.1.6 on the top left.

    • Otherwise (Yes), the request is forwarded to Authelia (to the right) for authentication checks.

  • 04b: For all sites requiring authentication, Authelia checks if the user session has a valid user authenticated session cookie. If it is still valid, Authelia forwards the request on to the destination site, as shown in this example 05b.

  • 05b: If there is no existing session (new request) cookie, or the session has expired (configurable duration in Authelia), the request is forwarded to the Authelia login page.

  • 06: Once the user enters his credentials, Authelia checks these against the OpenLDAP and MySQL database servers before allowing the user session to proceed to its final destination 07.

Authelia Configuration

/etc/authelia/configuration.yml (Created 6 Jul 2025)
  1##############################################################################
  2#                   Authelia configuration  thehomelab.wiki                  #
  3##############################################################################
  4
  5# Reference URL: https://thehomelab.wiki/books/dns-reverse-proxy/page/setup-authelia-to-work-with-nginx-proxy-manager
  6log:
  7  level: 'info'
  8  format: 'text'
  9  file_path: '/var/log/authelia/authelia.log'
 10
 11# To generate 32 bit lenght key: $ authelia crypto rand --length 32 --charset alphanumeric
 12# See https://www.authelia.com/reference/guides/generating-secure-values/
 13identity_validation:
 14  reset_password:
 15    jwt_secret: 'BuOBAq--some hex secret code generated with authelia--xX24S07dcD'
 16    jwt_lifespan: '5 minutes'
 17    jwt_algorithm: 'HS256'
 18
 19totp:
 20  disable: true
 21  issuer: thomas-pk.com
 22  algorithm: 'sha1'
 23  digits: 6
 24  period: 30
 25  skew: 1
 26  secret_size: 32
 27
 28server:
 29  address: 'tcp://:9091'
 30  endpoints:
 31    authz:
 32      auth-request:
 33        implementation: 'AuthRequest'
 34
 35# Passkeys see https://www.authelia.com/reference/guides/webauthn/
 36authentication_backend:
 37  password_reset:
 38    disable: true
 39    custom_url: ''
 40  password_change:
 41    disable: true
 42  ldap:
 43    address: 'ldap://192.168.1.12'
 44    implementation: 'custom'
 45    timeout: '5s'
 46    start_tls: false
 47#    tls:
 48#      server_name: '192.168.1.12'
 49#      skip_verify: true
 50#      minimum version: 'TLS1.2'
 51    pooling:
 52      enable: false
 53      count: 5
 54      retries: 2
 55      timeout: '10 seconds'
 56    base_dn: 'DC=thomas-pk,DC=com'
 57    additional_users_dn: 'OU=Users'
 58    users_filter: '(&({username_attribute}={input})(objectClass=inetOrgPerson))'
 59    additional_groups_dn: 'OU=Groups'
 60    groups_filter: '(&(member={dn})(objectClass=posixGroup))'
 61    group_search_mode: 'filter'
 62    permit_referrals: false
 63    permit_unauthenticated_bind: false
 64    permit_feature_detection_failure: false
 65    user: 'CN=admin,DC=thomas-pk,DC=com'
 66    password: 'LDAP password'
 67    attributes:
 68      distinguished_name: 'distinguishedName'
 69      username: 'uid'
 70      display_name: 'displayName'
 71      family_name: 'sn'
 72      given_name: 'givenName'
 73      middle_name: 'middleName'
 74      nickname: ''
 75      gender: ''
 76      birthdate: ''
 77      website: 'wWWHomePage'
 78      profile: ''
 79      picture: ''
 80      zoneinfo: ''
 81      locale: ''
 82      phone_number: 'telephoneNumber'
 83      phone_extension: ''
 84      street_address: 'streetAddress'
 85      locality: 'l'
 86      region: 'st'
 87      postal_code: 'postalCode'
 88      country: 'c'
 89      mail: 'mail'
 90      member_of: 'memberOf'
 91      group_name: 'cn'
 92      extra:
 93        extra_example:
 94          name: ''
 95          multi_valued: false
 96          value_type: 'string'
 97
 98access_control:
 99  default_policy: deny
100  rules:
101    # Rules applied to everyone
102    - domain:
103        - "www.thomas-pk.com"
104      policy: bypass
105    - domain: # Proxies only requiring username and password
106        - "history.thomas-pk.com"
107      policy: two_factor
108
109session:
110  name: authelia_session
111  # This secret can also be set using the env variables AUTHELIA_SESSION_SECRET_FILE
112  secret: BEc-- some hex code --VE
113  expiration: 3600 # 1 hour
114  inactivity: 180 # 3 minutes for testing
115  cookies:
116    - domain: thomas-pk.com # Needs to be your root domain
117      authelia_url: 'https://login.thomas-pk.com'
118      default_redirection_url: 'https://www.thomas-pk.com'
119
120regulation:
121  max_retries: 0
122  find_time: 2m
123  ban_time: 10m
124
125theme: dark   # options: dark, light
126
127storage:
128  encryption_key: 'cOzD5-- some hex encryption key generated by Authelia --GYxKQcO9'
129  mysql:
130    address: 'tcp://192.168.1.11:3306'
131    database: 'authelia'
132    username: 'authelia'
133    password: 'MySQL password'
134    timeout: '5s'
135
136notifier:
137  smtp:
138    address: 'submission://smtp.gmail.com:587'
139    username: 'your_gmail_user_id@gmail.com'
140    password: 'Your gmail app password'
141    sender: "Authelia <admin@thomas-pk.com>"
142#    timeout: '10s'
143#    identifier: 'localhost'
144#    subject: "[Authelia] {title}"
145#    startup_check_address: 'thomas.pk@gmail.com'
146#    disable_require_tls: false # set to true if your domain uses no tls or ssl only
147#    disable_html_emails: false # set to true if you don't want html in your emails
148#    tls:
149#      server_name: smtp.gmail.com
150#      skip_verify: false
151#      minimum_version: TLS1.2
152
153webauthn:
154  disable: false
155  enable_passkey_login: true
156  display_name: 'thomas-pk.com'
157  attestation_conveyance_preference: 'indirect'
158  timeout: '60 seconds'
159  filtering:
160    permitted_aaguids: []
161    prohibited_aaguids: []
162    prohibit_backup_eligibility: false
163  selection_criteria:
164    attachment: ''
165    discoverability: 'preferred'
166    user_verification: 'preferred'
167  metadata:
168    enabled: false
169    validate_trust_anchor: true
170    validate_entry: true
171    validate_entry_permit_zero_aaguid: false
172    validate_status: true
173    validate_status_permitted: []
174    validate_status_prohibited:
175      - 'REVOKED'
176      - 'USER_KEY_PHYSICAL_COMPROMISE'
177      - 'USER_KEY_REMOTE_COMPROMISE'
178      - 'USER_VERIFICATION_BYPASS'
179      - 'ATTESTATION_KEY_COMPROMISE'

The Authelia configuration.yml file for my domain.

What’s next

  • Enabling TLS connection to OpenLDAP

  • Getting my head around how to organise user entries in LDAP. This is new technology for me and its only after working with Authelia on this project I understood the importance of LDAP.