kjdev / nginx-auth-jwt

Nginx module for the authenticate using JWT
MIT License
24 stars 16 forks source link

Why disabling auth_jwt_validate_sig in the token verification subrequest? #4

Open jirutka opened 1 year ago

jirutka commented 1 year ago

What’s the reason for disabling signature verification in the ID token verification subrequest?

https://github.com/kjdev/nginx-auth-jwt/tree/main/example#changed-setting-for-id-token-verification

kjdev commented 1 year ago

In the preaccess phase, subrequests are not handled properly, so the verification process is not performed.

jirutka commented 1 year ago

Can you please elaborate, how are they not handled properly? Also, this is something worth mentioning in the readme.

Related question, is it possible to somehow run auth_jwt before auth_request?

kjdev commented 1 year ago

Can you please elaborate, how are they not handled properly? Also, this is something worth mentioning in the readme.

Annotated.

see: https://github.com/kjdev/nginx-auth-jwt/blob/main/README.md?plain=1#L228

Related question, is it possible to somehow run auth_jwt before auth_request?

When combined with auth_reqest it looks like this.

config:

# # auth_jwt_conf
# auth_jwt "" token=$session_jwt;
# error_page 401 = @oidc_error;
# auth_jwt_key_request /_jwks_uri;
# proxy_pass http://my_backend;

#OK: proxy_pass content
location = /auth/ok {
    include auth_jwt_conf;
    auth_request /auth_request/200;
    auth_jwt_validate_alg RS256;
}
# NG: 403 error page
location = /auth/ng {
    include auth_jwt_conf;
    auth_request /auth_request/403;
    auth_jwt_validate_alg RS256;
}
# NG: @oidc_error page
location = /auth/ok/invalid {
    include auth_jwt_conf;
    auth_request /auth_request/200;
    auth_jwt_validate_alg ES256; # invalid auth_jwt
}
# NG: @oidc_error page
location = /auth/ng/invalid {
    include auth_jwt_conf;
    auth_request /auth_request/403;
    auth_jwt_validate_alg ES256; # invalid auth_jwt
}

location = /auth_request/200 {
    return 200 "OK";
}
location = /auth_request/403 {
    return 403 "Forbidden";
}
jirutka commented 1 year ago

see: https://github.com/kjdev/nginx-auth-jwt/blob/main/README.md?plain=1#L228

I see now, I didn’t understand what exactly it meant before. Why are nested in-memory subrequest a problem?

When combined with auth_reqest it looks like this.

The problem is with $jwt_ variables, they are not set when the auth_request is executed. I’ve tried many workarounds (with njs), but nothing helped. What I want to achieve is to validate some claims with custom logic (role-based access control).

kjdev commented 1 year ago

I'm not sure if it's possible without two steps since they are both access faces.

upstream auth_request_backend {
    zone auth_request_backend 64k;
    server 127.0.0.1:8889;
}
server {
    listen 8889;
    location / {
        # valid auth_request
        auth_request /test;
        proxy_set_header username "$http_username";
        proxy_pass http://my_backend;
    }
    location /test {
        if ($http_username ~* "XXX") {
            return 200;
        }
        return 403;
    }
}

server {
    location /auth/test {
        # valid auth_jwt
        auth_jwt_validate_alg RS256;
        auth_jwt "" token=$session_jwt;
        error_page 401 = @oidc_error;
        auth_jwt_key_request /_jwks_uri;
        proxy_set_header username $jwt_claim_sub;
        proxy_pass http://auth_request_backend;
    }
}

Can we do this by adjusting the execution phase and variable assignment process?

jirutka commented 1 year ago

This workaround doesn’t look very good. :/

If auth_jwt_key_file is used instead of auth_jwt_key_request, then signature validation can be performed even in a subrequest, right?

It might be helpful if the module also accepts JWKS as a value (JSON encoded as a string), then I could more easily handle it myself from njs.

jirutka commented 1 year ago

Aha, nginx (not this module) forbids nested subrequests, that’s the problem we face here. I found it in https://github.com/nginx/njs/issues/339#issuecomment-692293250. However, inside njs, I can use fetch… except js_set doesn’t support async functions (which fetch is).