BTBurke / caddy-jwt

JWT middleware for the Caddy server
MIT License
113 stars 40 forks source link

Extract and consider all valid tokens found in the request #35

Closed sebaacuna closed 1 year ago

sebaacuna commented 6 years ago

Multiple tokens will be considered regardless of the method of delivery, if ANY token is valid, then validation is considered as passing and that token is used.

Previously, if multiple tokens were passed simultaneously (i.e. Authorization: Bearer token1 and also Cookie: jwt_token=token2) then only one token would be considered for validation (i.e. token1). If this token was invalid then other tokens which might be valid would be ignored.

This is relevant to a scenario where caddy is being used as a reverse proxy for multiple services behind an authentication wall (i.e. an intranet) using the jwt_token cookie, while backend apps might be using the Authentication header for their own JWT tokens. This would effectively "shadow" the cookie, effectively blocking access.


This is my first time writing any Go so sorry if I butchered anything too badly, I'm also not a frequent open source contributor so sorry if I'm not violating any rules of etiquette (and please do let me know).

BTBurke commented 6 years ago

Hey Sebastian, thanks for this pull request. I'm a little confused about the use case. If I understand this correctly, you want this middleware to consider multiple tokens passed in a single request, some of which may be invalid?

I haven't thought about this very much yet, but it seems like it could be a problem from a security perspective. It seems to me that a client should send only one token per request. This middleware can already proxy multiple requests containing different means of passing the token. For example, a request from a browser could pass it via cookie while a backend microservice can use the auth header. Since it's handled on a per-request basis, that works as expected, and should allow you to proxy connections from multiple clients using different token passing mechanisms.

What I don't understand is why a client would send multiple (possibly conflicting) tokens in a single request. To me, that would indicate a possibly malicious, or at least misconfigured, client.

The goal of this middleware is really to work for the simple use-cases. For more complicated use-cases like the one you're outlining here, it seems that the token validation should be moved to the backend service instead of this middleware.

sebaacuna commented 6 years ago

Hi Bryan, thanks for considering this PR and for the caddy-jwt middleware in the first place. It's been very helpful!

The use case providing the motivation for this PR is as follows:

I have a caddy instance proxying several backend apps that have varying methods of authentication themselves. I'm using Auth0 to provide a single means of ensuring all access has been authenticated using a company-valid account. The caddy-jwt is providing the Auth0 JWT token validation that will come in via the jwt_token cookie.

However, some of the backend apps use the Authorization: Bearer method to implement their own layer of app-specific authentication.

So what happens is that a user will:

  1. Hit Caddy and get redirected to fulfill the Auth0 login flow
  2. Authenticate on Auth0 and get a valid jwt_token cookie
  3. Validate in the caddy-jwt middleware and pass through into backend app's login challenge
  4. Authenticate in the app and get an app-specific Authorization: Bearer header set

At this point when the next request hits the caddy-jwt middleware again, the middleware will first check the Authorization header and deny access. The Authorization header is valid however (for the backend app) and the cookie is valid for the middleware.

Probably the cleanest solution would be to add some sort of directive to the middleware to specifically "turn on" any of the 3 validation methods. I for example would probably only care specifically for the cookie. So maybe with a feature like this my jwt directive would look something like:

jwt {
    path /
    redirect https://loginapp
    bearer ignore
    query ignore
}

Or, make all the methods "off" by default and enable them explicitly (which would be backwards incompatible), maybe also allow specifying a custom cookie name and querystring param instead of only jwt_token.

Sadly, this is far beyond what I can accomplish in a short time given my limited familiarity with Go and Caddy plugin implementations.

What I did find to be easy to implement and good enough at least for me was the current implementation in the PR.

There might also be other ways around my specific issue by way of juggling around headers and such in Caddy, but I didn't look much into it as I'm not using a Caddyfile but rather the caddy-docker-proxy plugin which limits some of my options and really makes me want to be able to simply have caddy-jwt be more flexible/customizable.

So, let me know what you think of the use case and if it's of any interest I'm happy to volunteer implementing the final version (although it might take some while). I get the concern about security, and I'm also not very sure what this PR would imply in that sense.

magikstm commented 5 years ago

I think this use-case could be fulfilled with PR #39.