Giter VIP home page Giter VIP logo

caddy-jwt's Introduction

AD

🔥 We're hiring! Message me for a referral :)

PROJECTS

  • httpin: Go - HTTP Request from/to Struct, i.e. Bi-directional Data Binding between Go Struct and http.Request (documentation)
  • 🦉 owl: Go - a Go Struct Tag Framework and Algorithm Driver
  • caddy-jwt: Go -Caddy Module for JWT Authentication (documentation)
  • distlock: Go - Simple distributed locks using Redis, MySQL, PostgreSQL, etc.
  • password: Go - Password Hashing & Verification
  • goenv: Go - Populate go struct instance with OS environment variables.
  • goplay: TypeScript - Embed Go Playground on your Website (demo)
  • v2raym: Bash - Dead simple v2ray client for macOS (in terminal)
  • droplet.sh: Bash - Import shell scripts like Go
  • python-fossil-delta: Python wrapper of the C implementation of Fossil Delta Encoding Algorithm
  • jsonla: C++ - Parse and manipulate JSON data structure

caddy-jwt's People

Contributors

a-p-z avatar ddl-ebrown avatar dependabot[bot] avatar francislavoie avatar ggicci avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

caddy-jwt's Issues

Build failing with caddy 2.6.4

The plugin cannot be built when using caddy 2.6.4.

panic: internal error: can't find reason for requirement on github.com/google/[email protected]

goroutine 1 [running]:
cmd/go/internal/modget.(*resolver).updateBuildList.func1({{0xc000029260?, 0xc001021f20?}, {0xc0000b4660?, 0xc00031a908?}})
	/usr/local/go/src/cmd/go/internal/modget/get.go:1760 +0x114
cmd/go/internal/modget.(*resolver).updateBuildList(0xc000276100, {0xb313d0, 0xc00002a058}, {0x0, 0x0, 0x0})
	/usr/local/go/src/cmd/go/internal/modget/get.go:1765 +0x597
cmd/go/internal/modget.(*resolver).applyUpgrades(0xc000276100, {0xb313d0, 0xc00002a058}, {0x0?, 0x2?, 0x472485?})
	/usr/local/go/src/cmd/go/internal/modget/get.go:1312 +0x105
cmd/go/internal/modget.runGet({0xb313d0, 0xc00002a058}, 0xc000028498?, {0xc0000241c0, 0x2, 0x2})
	/usr/local/go/src/cmd/go/internal/modget/get.go:351 +0x45e
main.invoke(0xe2cfc0, {0xc000024190, 0x5, 0x5})
	/usr/local/go/src/cmd/go/main.go:225 +0x34e
main.main()
	/usr/local/go/src/cmd/go/main.go:179 +0x7d1
2023/02/27 10:26:24 [FATAL] exit status 2

I'm using the following Dockerfile:

FROM caddy:2-builder-alpine AS builder

RUN xcaddy build \
    --with github.com/ggicci/caddy-jwt

FROM caddy:2-alpine

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

I believe this to be an upstream issue with go: golang/go#56494

I think all that needs to be updated is the caddy version in the go.mod file.
This is already known by caddy: caddyserver/caddy#5301

Pass sign_key as environment variable

Hi, this plugin works in principle great and reliable. However, is there any means of passing the sign key as an environment variable? Currently, in our pipelines, we're replacing the sign_key in our caddyfile via sed, but his does not seem like a clean approach. However, we did not succeed in directly passing the sign_key as an environment variable directly to Caddy similar to the approach explained in the docs.

Are we missing something here (if so, any guidance is appreciated and we would love to read something about it in the docs) or would this be an additional feature? In both cases, this would surely help #1

bump version to 1.0.0

I'm planing to publish the first stable release of this program. If any of you were using this plugin in your production environment, please feel free to leave a comment below. A breif description of your application scenarios will bring great helps ❤️

`Key is of invalid type` when validating token by asymmetric signing algorithms

I'm trying to get this module to work, and I've created a simple test case. I'm able to generate a rs256 token that I've validated works with jwt.io using the public/private key, but when I run it I got the following error:

2022/05/19 22:12:58.606	ERROR	http.authentication.providers.jwt	invalid token	{"token_string": "eyJhbGciOiJSUzI1…dEGPpt3q-wTcu6iQ", "error": "key is of invalid type"}
2022/05/19 22:12:58.606	ERROR	http.handlers.authentication	auth provider returned error	{"provider": "jwt", "error": "key is of invalid type"}

I'm generating the keys with:

openssl genrsa -out test-rs256-privkey.pem
openssl rsa -in  test-rs256-privkey.pem -pubout > test-rs256-pubkey.pem

For the sign_key I'm using openssl base64 -A < test-rs256-pubkey.pem to create the base64 string.

Caddyfile:

blah.local:7000 {
  respond "blah.local:7000"
}

blah.local:7001 {

  route * {
    jwtauth {
      sign_key xxx==
      #from_query access_token token
      from_header X-Api-Token
      #from_cookies user_session
    }
  }

  respond "blah.local:7001 protected"
}

It's not clear if the sign_key is the issue, or the authorization token. Would the way I'm creating that string be the correct way of doing it?

Getting "loaded_keys": -1 when using jwk_url

Hi. I am trying to use jwk_url using FusionAuth's endpoint (response example down below), but when I try to do I get am error saying that kid not found in JWKs, even though I have verified manually and it is there.

On server start I saw the following log, and the loaded_keys struck me as weird:

{"level":"info","ts":1688560980.1593323,"logger":"http.authentication.providers.jwt","msg":"using JWKs from URL","url":"http://fusionauth:9011/.well-known/jwks.json","loaded_keys":-1}

My config looks as follows:

(auth_token) {
	jwtauth {
		jwk_url "http://fusionauth:9011/.well-known/jwks.json"
		issuer_whitelist VALUE
		audience_whitelist VALUE
		user_claims sub email preferred_username
	}
}

Response of http://fusionauth:9011/.well-known/jwks.json:

{
  "keys" : [
    {
      "alg" : "RS256",
      "e" : "AQAB",
      "kid" : "VALUE",
      "kty" : "RSA",
      "n" : "VALUE",
      "use" : "sig",
      "x5c" : [
        "VALUE"
      ],
      "x5t" : "VALUE",
      "x5t#S256" : "VALUE"
    }
  ]
}

I am using version 0.9.0 of the caddy-jwt module with caddy 2.6.4.

Feature Request: Support nested claim path

Current implementation can only get non standard jwt claim value from top level, for example

{
    "sub": "1234",
    "iss": "http://myissuer.com",
    "aud": "myaudience",
   ... other standard jwt claims
  
   "role": "role"
}

we can get role claim without problem with adding meta_claims "role" to configuration

However sometimes custom jwt claim is in nested format, for example :

{
    "sub": "1234",
    "iss": "http://myissuer.com",
    "aud": "myaudience",
   ... other standard jwt claims
  
   "user_info": {
       "role": "admin",      
   }
}

Maybe we can use dot separated path, to track claim we need.
For example to get role claim from above example, we can write this in configuration :
meta_claims "user_info.role -> role"

if enable jwtauth ,then caddy cannot start .

host.xxx  {
      reverse_proxy  http://wapi.xxx
      jwtauth {
          sign_key 5bsddsdsd
          sign_alg HS256
          from_query access_token token
          from_header authorization
      }
}

directive 'jwtauth' is not an ordered HTTP handler, so it cannot be used here.

or

{
	order jwtauth before basicauth
}
host.xxx  {
      reverse_proxy  http://wapi.xxx
      jwtauth {
          sign_key 5bsddsdsd
          sign_alg HS256
          from_query access_token token
          from_header authorization
      }
}

adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first

host.xxx  {
        route {
         order jwtauth before basicauth
       }
}

during parsing: unrecognized directive: order - are you sure your Caddyfile structure (nesting and braces) is correct?

How to Use it?

JWT header's alg is not taken into consideration when using JWK URL

Although the comment here states:

// We will try to determine the algorithm automatically from the following sources:
// 1. The "alg" field in the JWT header.
// 2. The "alg" field in the matched JWK (if JWKURL is provided).
// 3. The value set here.
SignAlgorithm string `json:"sign_alg"`

in keyProvider(), if JWK url is used, then alg from JWT header is not used, and if the JWK provider does not include alg field in the response, it will lead to an error unsupported signature algorithm

if ja.usingJWK() {
	...
	// sig.ProtectedHeaders().Algorithm() is not taken into consideration in this branch
	sink.Key(ja.determineSigningAlgorithm(key.Algorithm()), key)
} else {
	sink.Key(ja.determineSigningAlgorithm(sig.ProtectedHeaders().Algorithm()), ja.parsedSignKey)
}

Cannot get it to work with pem

Hi, we have been trying to get caddy-jwt to work in our environment for a few days now to no avail.

We did realise earlier today that the latest 0.9.2 release requires Caddy 2.7.3 which does not appear to have hit Dockerhub yet. So we are using an earlier version. E.g

FROM caddy:2.7-builder AS builder
RUN xcaddy build --with github.com/ggicci/caddy-jwt@00ce67ff5c824293c51531287caab2ed0fe76743
<snip>

The above is not throwing any errors and we are now testing our Caddyfile

{
	auto_https off
	order jwtauth before basicauth
}

:80 {
	root * /srv
	file_server {
		index index.html
	}
	route {
		jwtauth {
			sign_alg RS256
			sign_key REDACTED
			from_query access_token token
			user_claims openid userprofile email
		}
	}
}

The errors we see now all appear to relate to signing. We started off using jwk_url pointing to https://login.microsoftonline.com/common/discovery/keys and that didn't work. So we decided to convert our key to a PEM file in the format

-----BEGIN RSA PUBLIC KEY-----
REDACTED
REDACTED
REDACTED
REDACTED
REDACTED
-----END RSA PUBLIC KEY-----

But could not see how to add that to the Caddyfile according to the instructions in the README since it is multiple lines. We tried making it all one line with escaped line breaks (e.g. \n). We tried with and without the --- HEADER --- strings. We have tried base64 encoding it. e.g

sign_key LS0tLS1CRUdJTiBS... base64 encoded PEM
sign_key -----BEGIN CERTIFICATE-----\nMIIDBTCCAe2gAwIBAgIQGQ6YG6NleJxJGDRAwAd... replaced line endings with escaped new lines

What is the correct way to represent a pem file in the sign_key variable?

We are passing our JWT in the query string of a GET, e.g. http://localhost:9990/index.html?token=eyJ0eXAiOiJKV1QiLCJu... where the token decodes properly in https://jwt.io (It should be noted that jwt.io always shows Invalid Signature, but we have come to expect that from experience with other providers)

We have since learned that Microsoft provides https://jwt.ms that is MS specific (version of a standard??). Using that I believe I have deduced the correct audience and issuer whitelists as our client id and tenant id respectivley

But the best we can get is

{"level":"error","ts":1692049376.9480076,"logger":"http.authentication.providers.jwt","msg":"invalid token","token_string":"eyJ0eXAiOiJKV1Qi…qPsS9swO7UsTwypw","error":"could not verify message using any of the signatures or keys"}
{"level":"error","ts":1692049376.9480765,"logger":"http.handlers.authentication","msg":"auth provider returned error","provider":"jwt","error":"could not verify message using any of the signatures or keys"}

I suspect a lot of our challenge is with Microsoft specific values. But knowing how to properly form a sign_key for a multi-line pem will help.

401 response on OPTIONS

During testing this plugin we noticed having issues when trying to perform a GET Operation from Browser Chrome. Chrome was execution a preflight operation where it is first requesting OPTIONS to the endpoint before executing a GET. Since OPTIONS does not contain the password in case it was sent within the Headers, OPTIONS is refused with a 401. This can cause a CORS issue on the GET operation.

We found a workaround by explicitely excluding OPTIONS from the jwt-check. But we wonder if this should be respected within this plugin itself :).

This is the example for the workaround:

<your-domain> {
	@exclude-options {
		not method OPTIONS
	}

	route @exclude-options {
		jwtauth {
			sign_key "
<JWTAUTH>
    "
			from_header X-Api-Token
			issuer_whitelist <Your Issuer>
			audience_whitelist <audience>
		}
	}
	respond "hello world"
}

Improve error message on missing kid header

if you use jwk url and do not have a kid in the jwt token header you will get the following error message:
caddy-caddy-1 | {"level":"error","ts":1683200873.3749237,"logger":"http.handlers.authentication","msg":"auth provider returned error","provider":"jwt","error":"key provider 0 failed: key not found: "}
Took me quite some time to understand what was going on.

kid := sig.ProtectedHeaders().KeyID()

I would suggest:

if kid is empty or nil {
 return fmt.Errorf("JWT key needs a header called kid matching the key id");
}

or change implementation to go through all keys instead of relying on the optional kid header to match the jwk.

Nice Module thx a lot.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.