How to Pass Authorization Headers from NGINX auth_request to Client for JWT Token Refresh


2 views

When implementing JWT authentication with token refresh functionality in NGINX, developers often face difficulties propagating refreshed tokens back to clients through the auth_request mechanism. The standard configuration doesn't automatically forward headers from the auth subrequest to the client.

Here's what typically happens in the described setup:

Client → NGINX → auth_module (verifies token) → NGINX → backend → Client

The breakpoint occurs when the auth_module generates a new Authorization header - it gets lost during the response journey back to the client.

Here's the corrected NGINX configuration that properly handles header propagation:

# Auth endpoint configuration
location = /jwtverify {
  internal;
  proxy_pass http://auth-module:8080/auth/verify;
  proxy_pass_request_body off;
  proxy_set_header Content-Length "";
  proxy_set_header X-Original-URI $request_uri;
  
  # Capture the potentially refreshed Authorization header
  auth_request_set $auth_header $upstream_http_authorization;
}

# Protected endpoint configuration
location /profile {
  auth_request /jwtverify;
  
  # Set the Authorization header from auth subrequest
  auth_request_set $auth_header $upstream_http_authorization;
  
  # Only pass the new header if it exists
  proxy_set_header Authorization $auth_header;
  
  proxy_pass http://private-profile:80;
}

The solution relies on these crucial elements:

  • Using auth_request_set to capture headers from the auth subrequest
  • Storing the header value in a variable ($auth_header)
  • Conditionally applying the header in the main request using proxy_set_header

For production environments, consider these enhancements:

# Add error handling
error_page 401 = @error401;

location @error401 {
  return 401 '{"error": "Unauthorized"}';
}

# Set CORS headers if needed
add_header 'Access-Control-Expose-Headers' 'Authorization';
add_header 'Access-Control-Allow-Headers' 'Authorization';

Verify the refresh flow with this test sequence:

  1. Make initial request with nearing-expiration token
  2. Check response headers for new Authorization token
  3. Verify subsequent requests work with the new token

When implementing JWT authentication with NGINX's auth_request, a common requirement is to pass refreshed tokens back to clients. The standard configuration often fails to propagate headers set by the auth service. Here's why this happens and how to fix it.

In the described setup:

location /profile {
  auth_request /jwtverify;
  auth_request_set $authorization $upstream_http_authorization;
  proxy_set_header authorization $authorization;
  proxy_pass http://private-profile:80;
}

The key limitation is that auth_request_set only captures headers for use within NGINX - it doesn't automatically send them to the client.

To properly pass headers through the entire chain, we need to:

  1. Capture headers from the auth service
  2. Apply them to both the upstream request and client response

Here's the working configuration:

location /profile {
  auth_request /jwtverify;
  
  # Capture auth headers from the auth service
  auth_request_set $auth_header $upstream_http_authorization;
  
  # Pass to upstream service
  proxy_set_header Authorization $auth_header;
  
  # Also set in response to client
  add_header Authorization $auth_header;
  
  proxy_pass http://private-profile:80;
}

location = /jwtverify {
  internal;
  proxy_pass http://auth-module:8080/auth/verify;
  proxy_pass_request_body off;
  proxy_set_header Content-Length "";
  proxy_set_header X-Original-URI $request_uri;
}

When implementing this solution:

  • The add_header directive only works for successful responses (200, 201, etc.)
  • For error cases, you'll need additional error_page handling
  • Multiple add_header directives in the same block will override each other

Verify the header propagation with curl:

curl -v -H "Authorization: Bearer old.token" https://yourservice.com/profile

Check for the new token in both the response headers and the subsequent requests.

For more complex scenarios involving multiple headers or conditional logic, consider using NGINX JavaScript:

js_import /etc/nginx/auth.js;

location /profile {
  auth_request /jwtverify;
  js_header_filter auth.processHeaders;
  proxy_pass http://private-profile:80;
}

With corresponding JavaScript:

function processHeaders(r) {
  if (r.headersIn['x-new-token']) {
    r.headersOut['Authorization'] = r.headersIn['x-new-token'];
  }
}