I have been using NGINX as a reverse proxy and recently decided I needed to add authentication to a route on a website. I realised that there area multiple NGINX modules that could allow me to handle the authentication through NGINX (see links below). So, I build a single-sing-on login page that integrates auth0 to test how this would work.
All modules are similar and allow you to specify an auth_jwt_key
(for validation of the JWT) as well as a variable to where the JWT (auth_jwt
) is stored. I decided to store the JWT in a cookie.
Unfortunately, I can not get the validation through NGINX to work and keep seeing a 401 unauthorized
return code.
Here is the part of the flask app, where I am handling the auth0 login and storing the JWT into a cookie:
@app.route('/callback')
def callback_handling():
token = auth0.authorize_access_token()
response = redirect('/dashboard')
response.set_cookie('lt_jwt', value=token.get('id_token'), max_age=token.get('expires_in'))
return response
Can you see something wrong with this? The resulting cookie looks something like this (I removed most of it for readability): lt_jwt eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA staging-auth0-login.scapp.io / 9/13/2018, 1:55:45 PM 1.03 KB
I can put the cookie value into jwt.io and decode it properly, but my problem is that the mentioned NGINX modules have issues decoding it.
Here is an example NGINX config, where I am setting up the authentication:
location = /dashboard {
auth_jwt_key "AUTH0_CLIENT_SECRET";
auth_jwt $cookie_lt_jwt;
root /usr/src/lt/nginx;
try_files /dashboard.html =404;
}
Basically, I never get to see dashboard.html
and always get the 401 unauthorized
. The NGINX error.log
shows that decoding the JWT failed: [warn] 64#64: *23 JWT: failed to parse jwt
, which in this case is an error log from the custom nginx module I used:
// Validate the jwt
if (jwt_decode(&jwt, jwt_data, conf->jwt_key.data, conf->jwt_key.len))
{
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "JWT: failed to parse jwt");
return NGX_HTTP_UNAUTHORIZED;
}
Unfortunately, it's not super easy to debug it, but I received a similar response from another custom NGINX module that I also tested: jwt_verify: error on decode: SUCCESS
, which is a result of this code segment:
jwt_t* token;
int err = jwt_decode(&token, token_data, alcf->key.data, alcf->key.len);
if (err) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, errno,
"jwt_verify: error on decode: %s", strerror(errno));
return ngx_http_auth_jwt_set_realm(r, &alcf->realm);
}
So in both cases jwt_decode
is called and fails (even though it's error code apparently is SUCCESS
).
The reason I am asking here is that I feel I might be doing something conceptually wrong here:
- formatting the cookie (I have seen jwt cookies looking like this:
Bearer eyJ0eX[...]SkRNZyJ9.eyJnaXZ[...]kzNDV9.d3Tzr[...]NzbA
- assuming that an auth0 generated token can be used this way
- ...?
Please let me know if you have any insight or good working example with NGINX + auth0. I have read this article https://auth0.com/blog/use-nginx-plus-and-auth0-to-authenticate-api-clients/ by auth0 detailing how a very similar NGINX Pro module could be used, but I don't have access to that commercial module.