yum upgrades for production use, this is the repository for you.
Active subscription is required.
Every system administrator managing an enterprise network knows the frustration: users must type their credentials into yet another login prompt, even though they already authenticated when they logged into their workstation. Help desk tickets pile up with password reset requests. Sensitive credentials travel over the network in base64-encoded Basic authentication headers that any packet sniffer can decode. In Active Directory environments, this problem is especially painful because a perfectly good authentication infrastructure — Kerberos — already exists but goes unused by the web server. Implementing NGINX Kerberos authentication changes this entirely.
With the SPNEGO module, NGINX participates directly in your existing Kerberos realm, enabling transparent Single Sign-On (SSO). Domain-joined browsers like Chrome, Firefox, and Edge automatically negotiate authentication using the user’s existing Kerberos ticket — no password prompt, no credentials sent over the wire, no extra login step. The user simply opens the intranet page and is immediately authenticated.
This guide covers everything you need to set up NGINX Kerberos authentication: from installation and keytab creation to advanced features like principal-based authorization and constrained delegation. If you are looking for other NGINX authentication options, see also our articles on Phantom Token authentication and JWT authentication.
How SPNEGO Authentication Works
SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) is the protocol that enables Kerberos authentication over HTTP. Understanding the authentication flow helps you troubleshoot issues and make informed configuration decisions.
Here is what happens when a user visits a protected page:
- Initial request: The browser sends a normal HTTP request without credentials.
- 401 challenge: NGINX responds with
HTTP 401 Unauthorizedand aWWW-Authenticate: Negotiateheader. - Ticket request: The browser requests a service ticket from the Key Distribution Center (KDC) for the NGINX server’s Service Principal Name (SPN).
- Token exchange: The browser re-sends the request with an
Authorization: Negotiate <base64-token>header containing the Kerberos service ticket. - Validation: NGINX decrypts the ticket using its keytab file, validates the user’s identity, and grants access.
- Response: NGINX sets
$remote_userto the authenticated principal and forwards the request to the backend.
This entire exchange happens automatically and invisibly in domain-joined browsers. The user sees the page load with no login prompt.
SPNEGO vs. Basic Authentication
| Feature | SPNEGO/Kerberos | Basic Auth |
|---|---|---|
| Password sent over network | No (ticket-based) | Yes (base64-encoded) |
| User interaction required | None (transparent) | Password prompt |
| Requires TLS for safety | No (already encrypted) | Absolutely yes |
| Works with Active Directory | Native integration | Requires separate user store |
| Single Sign-On | Yes | No |
Installation
RHEL, CentOS, AlmaLinux, Rocky Linux
Install the module from the GetPageSpeed RPM repository:
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-spnego-http-auth
Then load the module at the top of your nginx.conf:
load_module modules/ngx_http_auth_spnego_module.so;
You also need the Kerberos client libraries for keytab management:
sudo dnf install krb5-workstation
Debian and Ubuntu
First, set up the GetPageSpeed APT repository, then install:
sudo apt-get update
sudo apt-get install nginx-module-spnego-http-auth
On Debian/Ubuntu, the package handles module loading automatically. No
load_moduledirective is needed.
Install the Kerberos client tools:
sudo apt-get install krb5-user
Prerequisites
Before configuring NGINX, you need a working Kerberos environment with a keytab file for NGINX.
1. Configure the Kerberos Client
Edit /etc/krb5.conf on the NGINX server to point to your KDC. For an Active Directory domain EXAMPLE.COM:
[libdefaults]
default_realm = EXAMPLE.COM
dns_lookup_realm = false
dns_lookup_kdc = true
[realms]
EXAMPLE.COM = {
kdc = dc01.example.com
admin_server = dc01.example.com
}
[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM
2. Create the Service Principal
On your Active Directory domain controller (or MIT KDC), create a service principal for the NGINX server. The SPN must match the hostname that clients use to access the server.
Active Directory (using setspn on Windows):
setspn -A HTTP/intranet.example.com NGINX-SVC
MIT Kerberos (using kadmin):
kadmin -q "addprinc -randkey HTTP/intranet.example.com@EXAMPLE.COM"
3. Generate the Keytab File
Export the service principal’s key into a keytab file that NGINX can read.
Active Directory (using ktpass on Windows):
ktpass -princ HTTP/intranet.example.com@EXAMPLE.COM -mapuser NGINX-SVC@EXAMPLE.COM -crypto AES256-SHA1 -ptype KRB5_NT_PRINCIPAL -pass * -out http.keytab
MIT Kerberos:
kadmin -q "ktadd -k /etc/nginx/http.keytab HTTP/intranet.example.com@EXAMPLE.COM"
4. Deploy the Keytab
Copy the keytab to the NGINX server and set strict permissions:
sudo cp http.keytab /etc/nginx/http.keytab
sudo chown root:nginx /etc/nginx/http.keytab
sudo chmod 440 /etc/nginx/http.keytab
The keytab contains the service’s secret key. Treat it like a private key file — if compromised, an attacker can impersonate your service.
5. Verify the Keytab
Confirm the keytab contains the correct principal:
klist -k /etc/nginx/http.keytab
Expected output:
Keytab name: FILE:/etc/nginx/http.keytab
KVNO Principal
---- --------------------------------------------------------------------------
2 HTTP/intranet.example.com@EXAMPLE.COM
Basic Configuration
The simplest NGINX Kerberos authentication configuration protects a location block with SPNEGO:
server {
listen 443 ssl;
server_name intranet.example.com;
ssl_certificate /etc/nginx/ssl/intranet.crt;
ssl_certificate_key /etc/nginx/ssl/intranet.key;
# Kerberos tokens can be large — increase header buffer size
large_client_header_buffers 8 32k;
location / {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
proxy_set_header X-Remote-User $remote_user;
proxy_set_header Authorization "";
proxy_pass http://backend;
}
}
Key points about this configuration:
auth_gss onenables SPNEGO authentication for the location.auth_gss_realmmust exactly match your Kerberos realm name (uppercase by convention).auth_gss_keytabpoints to the keytab file created earlier.auth_gss_service_nameis the service prefix of your SPN (typicallyHTTP).large_client_header_buffersaccommodates Kerberos tokens that can exceed the default 8 KB buffer, especially in Active Directory environments with many group memberships.proxy_set_header Authorization ""strips the Kerberos token before forwarding to the backend, preventing it from being logged or misinterpreted.$remote_usercontains the authenticated Kerberos principal after successful authentication.
Advanced Configuration
Restrict Access to Specific Principals
By default, any user who can obtain a valid service ticket is granted access. Use auth_gss_authorized_principal to restrict access to specific users:
location /admin {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
auth_gss_authorized_principal admin@EXAMPLE.COM;
auth_gss_authorized_principal ops@EXAMPLE.COM;
proxy_pass http://admin-backend;
}
Authenticated users not in the allowed list receive a 403 Forbidden response.
Regex-Based Principal Authorization
For more flexible access control, use auth_gss_authorized_principal_regex to match principals with regular expressions:
location /team {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
# Allow any principal starting with "team-"
auth_gss_authorized_principal_regex "^team-.*@EXAMPLE\.COM$";
proxy_pass http://team-backend;
}
You can combine exact and regex principals in the same location. A request is authorized if the authenticated principal matches any of the configured entries.
Disable Basic Authentication Fallback
By default, the module sends both WWW-Authenticate: Negotiate and WWW-Authenticate: Basic headers. This allows non-domain-joined clients to fall back to password authentication via Kerberos. However, Basic authentication sends credentials in cleartext (base64) and should be disabled when security is paramount:
location / {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
auth_gss_allow_basic_fallback off;
proxy_pass http://backend;
}
With auth_gss_allow_basic_fallback off, only the Negotiate challenge is sent. Clients that do not support SPNEGO will see a 401 error and cannot authenticate.
Credential Delegation
Credential delegation allows NGINX to forward the user’s Kerberos credentials to a backend application. This is useful when the backend needs to access other Kerberos-protected services on behalf of the authenticated user (for example, a web application that queries a Kerberized database).
location /app {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
auth_gss_delegate_credentials on;
fastcgi_param KRB5CCNAME $krb5_cc_name;
fastcgi_pass unix:/var/run/php-fpm.sock;
}
When credential delegation is enabled, the module stores the delegated credentials in a temporary credential cache file and exposes its path via the $krb5_cc_name variable. The backend application uses this environment variable to locate and use the delegated credentials.
Important: Credential delegation requires that the client’s Kerberos configuration allows forwarding tickets and that the service principal is trusted for delegation in the KDC.
Constrained Delegation (S4U2proxy)
Constrained delegation is a more secure alternative to full credential delegation. Instead of forwarding the user’s TGT, the service obtains a service ticket on behalf of the user using the S4U2proxy Kerberos extension. This limits which services the NGINX server can access on the user’s behalf.
location /api {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
auth_gss_delegate_credentials on;
auth_gss_constrained_delegation on;
auth_gss_service_ccache /tmp/krb5cc_nginx;
fastcgi_param KRB5CCNAME $krb5_cc_name;
fastcgi_pass unix:/var/run/php-fpm.sock;
}
In Active Directory, you must configure the NGINX service account for constrained delegation in the “Delegation” tab of the account properties, specifying which target services are allowed.
Local Name Mapping
The auth_gss_map_to_local directive applies Kerberos local name mapping rules (defined in krb5.conf) to the authenticated principal. This converts a Kerberos principal like jdoe@EXAMPLE.COM to a local username like jdoe:
location / {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
auth_gss_map_to_local on;
proxy_set_header X-Remote-User $remote_user;
proxy_pass http://backend;
}
The mapping rules in krb5.conf control the transformation. For example, to strip the realm for local users:
[realms]
EXAMPLE.COM = {
auth_to_local = RULE:[1:$1@$0](.*@EXAMPLE\.COM)s/@.*//
auth_to_local = DEFAULT
}
Controlling the $remote_user Format
By default, the module strips the realm from $remote_user. So a user authenticated as jdoe@EXAMPLE.COM appears as simply jdoe. To include the full principal with realm:
auth_gss_format_full on;
With this enabled, $remote_user contains jdoe@EXAMPLE.COM.
The auth_gss_force_realm directive ensures that the configured realm is always applied, even when a user authenticates with a different realm:
auth_gss_force_realm on;
Directive Reference
All directives can be used in http, server, location, and limit_except contexts unless noted otherwise.
| Directive | Default | Description |
|---|---|---|
auth_gss |
off |
Enable or disable SPNEGO/Kerberos authentication. |
auth_gss_realm |
none | The Kerberos realm name (e.g., EXAMPLE.COM). |
auth_gss_keytab |
/etc/krb5.keytab |
Path to the keytab file containing the service key. |
auth_gss_service_name |
none | Service principal prefix (typically HTTP). |
auth_gss_service_ccache |
none | Path for the service credential cache, used with constrained delegation. |
auth_gss_allow_basic_fallback |
on |
Send a Basic challenge alongside Negotiate, allowing password-based Kerberos authentication. |
auth_gss_authorized_principal |
none | Allow only the specified principal. Repeatable for multiple principals. |
auth_gss_authorized_principal_regex |
none | Allow principals matching the given PCRE regular expression. |
auth_gss_format_full |
off |
Include the Kerberos realm in $remote_user (e.g., user@REALM). |
auth_gss_force_realm |
off |
Force the configured realm on all authenticated users. |
auth_gss_map_to_local |
off |
Apply Kerberos local name mapping rules from krb5.conf. |
auth_gss_delegate_credentials |
off |
Accept and store delegated user credentials. |
auth_gss_constrained_delegation |
off |
Enable S4U2proxy constrained delegation. |
auth_gss_zone_name |
shm_zone |
Name of the shared memory zone used by the module. http context only. |
Variables
| Variable | Description |
|---|---|
$remote_user |
The authenticated Kerberos principal. Format depends on auth_gss_format_full and auth_gss_map_to_local settings. |
$krb5_cc_name |
Path to the delegated credential cache file (e.g., FILE:/tmp/jdoe_EXAMPLE.COM). Only set when auth_gss_delegate_credentials is enabled and the client delegates credentials. |
Performance Considerations
NGINX Kerberos authentication has minimal performance overhead compared to other authentication methods:
- No external service calls per request: Unlike LDAP authentication, SPNEGO validation is a local cryptographic operation using the keytab file. There is no network round-trip to a directory server.
- Shared memory zone: The module uses a small shared memory zone (64 KB by default) for internal coordination between worker processes.
- Header buffer sizing: Kerberos tokens in Active Directory environments can reach 10–20 KB due to PAC (Privilege Attribute Certificate) data containing group memberships. Set
large_client_header_buffers 8 32kto prevent400 Bad Requesterrors. This increases memory usage by approximately 256 KB per worker process. - Credential cache I/O: When credential delegation is enabled, the module writes temporary credential cache files to
/tmp. On high-traffic servers, consider mounting/tmpastmpfsto avoid disk I/O.
Security Best Practices
Disable Basic Authentication Fallback
The single most important hardening step is disabling Basic auth fallback. Basic auth sends passwords in base64 encoding, which is trivially decoded. Even over TLS, this exposes credentials to man-in-the-middle attacks if TLS termination happens upstream:
auth_gss_allow_basic_fallback off;
Protect the Keytab File
The keytab file is the security foundation of SPNEGO authentication. Apply strict filesystem permissions:
sudo chown root:nginx /etc/nginx/http.keytab
sudo chmod 440 /etc/nginx/http.keytab
On systems with SELinux enabled, ensure the keytab has the correct context:
sudo restorecon -v /etc/nginx/http.keytab
Use Principal-Based Authorization
Do not rely solely on successful Kerberos authentication for access control. Any domain user can obtain a service ticket. Use auth_gss_authorized_principal or auth_gss_authorized_principal_regex to restrict access to authorized users:
location /sensitive {
auth_gss on;
auth_gss_realm EXAMPLE.COM;
auth_gss_keytab /etc/nginx/http.keytab;
auth_gss_service_name HTTP;
auth_gss_allow_basic_fallback off;
auth_gss_authorized_principal_regex "^(admin|ops-team)@EXAMPLE\.COM$";
proxy_pass http://sensitive-backend;
}
Prefer Constrained Delegation Over Full Delegation
If your backend needs to act on behalf of the user, prefer constrained delegation (auth_gss_constrained_delegation on) over full credential delegation. Constrained delegation limits which services can be accessed and is controlled at the KDC level, reducing the blast radius of a compromised NGINX server.
Keep Clocks Synchronized
Kerberos is extremely sensitive to clock skew. A difference of more than 5 minutes between the client, NGINX server, and KDC will cause authentication failures. Ensure NTP is running on all systems:
sudo systemctl enable --now chronyd
Strip Credentials Before Forwarding
Always clear the Authorization header before proxying to backend services. This prevents the Kerberos token from being logged, cached, or misinterpreted by the backend:
proxy_set_header Authorization "";
Troubleshooting
“400 Bad Request — Request Header Or Cookie Too Large”
Kerberos tokens in Active Directory can be very large, especially for users in many groups. Increase the header buffer size:
large_client_header_buffers 8 32k;
If tokens still exceed 32 KB (users in hundreds of groups), increase to 64k.
“gss_accept_sec_context() failed”
This is the most common error. Check these in order:
- Clock synchronization: Run
dateon the NGINX server and compare with your KDC. Skew > 5 minutes causes failures. - SPN mismatch: The SPN in the keytab must match the hostname in the URL. If users access
intranet.example.com, the keytab must containHTTP/intranet.example.com@EXAMPLE.COM. - Keytab permissions: NGINX must be able to read the keytab. Check with
sudo -u nginx klist -k /etc/nginx/http.keytab. - DNS resolution: Reverse DNS for the NGINX server’s IP should resolve to the hostname in the SPN.
Browser Shows Password Prompt Instead of SSO
Ensure the browser trusts the site for Negotiate authentication:
Firefox: Navigate to about:config and set network.negotiate-auth.trusted-uris to your domain (e.g., .example.com).
Chrome/Edge: These browsers use the system Kerberos configuration. On Linux, ensure the user has a valid TGT (klist) and that the site is in the Kerberos-trusted zone.
All browsers: The URL hostname must exactly match the SPN. Accessing by IP address will not trigger SPNEGO.
Detecting NTLM Fallback
If a client sends an NTLM token instead of a Kerberos ticket, the module logs:
Detected unsupported mechanism: NTLM
NTLM is not supported. Ensure the client has a valid Kerberos TGT and that the SPN is correctly configured. NTLM fallback typically occurs when the client cannot contact the KDC or the SPN does not exist.
Enable Debug Logging
For detailed authentication diagnostics, enable debug-level logging:
error_log /var/log/nginx/error.log debug;
The module logs each step of the SPNEGO negotiation, including the decoded principal name, keytab lookup results, and GSSAPI error codes.
Conclusion
NGINX Kerberos authentication with the SPNEGO module eliminates password prompts for enterprise users, strengthens security by removing credentials from the wire, and integrates natively with Active Directory and MIT Kerberos environments.
The module is available from the GetPageSpeed repository for RHEL-based distributions and from the APT repository for Debian and Ubuntu.
