HAProxy Enterprise Documentation 2.7r1

Configuring a Proxy for OAuth Authorization

Here is how you should configure the proxy to receive and validate requests with tokens:

frontend myapi
  bind :80
  bind :443  ssl crt /etc/hapee-2.7/certs/foo.com/cert.crt alpn h2
  http-request redirect scheme https unless { ssl_fc }

  http-request deny content-type 'text/html' string 'Missing Authorization HTTP header' unless { req.hdr(authorization) -m found }

  # get header part of the JWT
  http-request set-var(txn.alg) http_auth_bearer,jwt_header_query('$.alg')

  # get payload part of the JWT
  http-request set-var(txn.iss) http_auth_bearer,jwt_payload_query('$.iss')
  http-request set-var(txn.aud) http_auth_bearer,jwt_payload_query('$.aud')
  http-request set-var(txn.exp) http_auth_bearer,jwt_payload_query('$.exp','int')
  http-request set-var(txn.scope) http_auth_bearer,jwt_payload_query('$.scope')

  # Validate the JWT
  http-request deny content-type 'text/html' string 'Unsupported JWT signing algorithm'  unless { var(txn.alg) -m str RS256 }
  http-request deny content-type 'text/html' string 'Invalid JWT issuer'  unless { var(txn.iss) -m str https://myaccount.auth0.com/ }
  http-request deny content-type 'text/html' string 'Invalid JWT audience'  unless { var(txn.aud) -m str https://api.mywebsite.com }
  http-request deny content-type 'text/html' string 'Invalid JWT signature'  unless { http_auth_bearer,jwt_verify(txn.alg,"/etc/hapee-2.7/pubkey.pem") -m int 1 }

  http-request set-var(txn.now) date()
  http-request deny content-type 'text/html' string 'JWT has expired' if { var(txn.exp),sub(txn.now) -m int lt 0 }

  # OPTIONAL: Deny requests that lack sufficient permissions
  http-request deny if { path_beg /api/ } { method GET } ! { var(txn.scope) -m sub read }
  http-request deny if { path_beg /api/ } { method DELETE POST PUT } ! { var(txn.scope) -m sub write }

  default_backend servers

backend servers
  balance roundrobin
  server web1 192.168.56.31:3000 check maxconn 30

Here's a breakdown of the configuration:

  • We get the token from the Authentication HTTP header by using the http_auth_bearer fetch method. The jwt_header_query converter then extracts fields from the token's header, and the jwt_payload_query converter extracts fields from the payload.

  • We store the fields in variables by using the http-request set-var directive.

  • We use the http-request deny directive to deny requests that fail validation in some way. This directive allows you to set a string parameter, which lets you return an error message to the user.

  • We verify the token's signature using the jwt_verify converter.

  • We relay valid requests to the backend named servers.

Here's how HAProxy Enterprise validates the token:

  • Was the token signed using an algorithm we support? In this case, yes, we allow RS256.

  • Can the token's signature be verified using the Auth0 public key that we downloaded?

  • Is the issuer the expected value, https://myaccount.auth0.com/, which is our Auth0 account name?

  • Is the audience the expected value, https://api.mywebsite.com, which is the Identifier we set for the API in Auth0?

  • Has the token expired? HAProxy Enterprise answers this question by subtracting the current timestamp from the expiration date timestamp.

  • Does the token's scopes field contain the permissions necessary to perform the requested action? Here we consider GET requests to be read actions and DELETE, POST, and PUT requests to be write actions.

Call your service at the address where the proxy is listening. In your request, the token should be set in the Authorization header.

$ curl --request GET \
      -k \
      --url https://192.168.56.20/ \
      --header 'authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6Ikp...'

See also


Next up

Bot Management