caddyjwt

package module
v0.0.0-...-1fe221b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2022 License: MIT Imports: 19 Imported by: 0

README

caddy-jwt

Go Workflow codecov Go Report Card Go Reference

A Caddy HTTP Module - who Facilitates JWT Authentication

This module fulfilled http.handlers.authentication middleware as a provider named jwt.

Documentation

Install

Build this module with caddy at Caddy's official download site. Or:

xcaddy --with github.com/ggicci/caddy-jwt

Sample Caddyfile

api.example.com {
	route * {
		jwtauth {
			sign_key TkZMNSowQmMjOVU2RUB0bm1DJkU3U1VONkd3SGZMbVk=
			from_query access_token token
			from_header X-Api-Token
			from_cookies user_session
			issuer_whitelist https://api.example.com
			audience_whitelist https://api.example.io https://learn.example.com
			user_claims aud uid user_id username login
			meta_claims "IsAdmin->is_admin" "settings.payout.paypal.enabled->is_paypal_enabled"
		}
		reverse_proxy http://172.16.0.14:8080
	}
}

NOTE:

  1. If you were using symmetric signing algorithms, e.g. HS256, encode your key bytes in base64 format as sign_key's value.
TkZMNSowQmMjOVU2RUB0bm1DJkU3U1VONkd3SGZMbVk=
  1. If you were using asymmetric signing algorithms, e.g. RS256, encode your public key in x.509 PEM format as sign_key's value.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArzekF0pqttKNJMOiZeyt
RdYiabdyy/sdGQYWYJPGD2Q+QDU9ZqprDmKgFOTxUy/VUBnaYr7hOEMBe7I6dyaS
5G0EGr8UXAwgD5Uvhmz6gqvKTV+FyQfw0bupbcM4CdMD7wQ9uOxDdMYm7g7gdGd6
SSIVvmsGDibBI9S7nKlbcbmciCmxbAlwegTYSHHLjwWvDs2aAF8fxeRfphwQZKkd
HekSZ090/c2V4i0ju2M814QyGERMoq+cSlmikCgRWoSZeWOSTj+rAZJyEAzlVL4z
8ojzOpjmxw6pRYsS0vYIGEDuyiptf+ODC8smTbma/p3Vz+vzyLWPfReQY2RHtpUe
hwIDAQAB
-----END PUBLIC KEY-----
  1. The priority of from_xxx is from_query > from_header > from_cookies.

Test it by yourself

git clone https://github.com/ggicci/caddy-jwt.git
cd caddy-jwt

# Build a caddy with this module and run an example server at localhost.
make example

TEST_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjk5NTU4OTI2NzAsImp0aSI6IjgyMjk0YTYzLTk2NjAtNGM2Mi1hOGE4LTVhNjI2NWVmY2Q0ZSIsInN1YiI6IjM0MDYzMjc5NjM1MTY5MzIiLCJpc3MiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbSIsImF1ZCI6WyJodHRwczovL2FwaS5leGFtcGxlLmlvIl0sInVzZXJuYW1lIjoiZ2dpY2NpIn0.O8kvRO9y6xQO3AymqdFE7DDqLRBQhkntf78O9kF71F8

curl -v "http://localhost:8080?access_token=${TEST_TOKEN}"
# You should see authenticated output:
#
# User Authenticated with ID: 3406327963516932
#
# And the following command should also work:
curl -v -H"X-Api-Token: ${TEST_TOKEN}" "http://localhost:8080"
curl -v -H"Authorization: Bearer ${TEST_TOKEN}" "http://localhost:8080"

NOTE: you can decode the ${TEST_TOKEN} above at jwt.io to get human readable payload as follows:

{
  "exp": 9955892670,
  "jti": "82294a63-9660-4c62-a8a8-5a6265efcd4e",
  "sub": "3406327963516932",
  "iss": "https://api.example.com",
  "aud": ["https://api.example.io"],
  "username": "ggicci"
}

How it works?

Module caddy-jwt behaves like a "JWT Validator". The authentication flow is:

   ┌──────────────────┐
   │Extract token from│
   │  1. query        │
   │  2. header       │
   │  3. cookies      │
   └────────┬─────────┘
            │
    ┌───────▼────────┐
    │   is valid?    │
    │using `sign_key`├────NO───────┐
    └───────┬────────┘             │
            │YES                   │
┌───────────▼───────────┐          │
│Populate {http.user.id}│          │
│  by `user_claims`     │          │
└───────────┬───────────┘          │
            │                      │
 ┌──────────▼───────────┐          │
 │is {http.user.id} set?├──NO(empty)
 └──────────┬───────────┘       │  │
            │YES(non-empty)     │  │
 ┌──────────▼───────────┐       │  │
 │Populate {http.user.*}│       │  │
 │   by `meta_claims`   │       │  │
 └──────────┬───────────┘       │  │
            │                   │  │
   ┌────────▼──────────┐ ┌──────▼──▼─────┐
   │   Authenticated   │ │Unauthenticated│
   │ Continue to Caddy │ │      401      │
   └───────────────────┘ └───────────────┘

flowchart by https://asciiflow.com/

References

Documentation

Overview

caddyjwt is a Caddy Module - who facilitates JWT authentication.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMissingSignKey   = errors.New("sign_key is required")
	ErrInvalidPublicKey = errors.New("invalid PEM-formatted public key")
	ErrInvalidIssuer    = errors.New("invalid issuer")
	ErrInvalidAudience  = errors.New("invalid audience")
	ErrEmptyUserClaim   = errors.New("user claim is empty")
)

Functions

This section is empty.

Types

type JWTAuth

type JWTAuth struct {
	// SignKey is the key used by the signing algorithm to verify the signature.
	//
	// For symmetric algorithems, use the key directly. e.g.
	//
	//     "<secret_key_bytes_in_base64_format>".
	//
	// For asymmetric algorithems, use the public key in x509 PEM format. e.g.
	//
	//     -----BEGIN PUBLIC KEY-----
	//     ...
	//     -----END PUBLIC KEY-----
	//
	// For remote JWK (JSON Web Keys), specify the URL. e.g.
	//
	//  https://www.gstatic.com/iap/verify/public_key-jwk
	SignKey string `json:"sign_key"`

	// FromQuery defines a list of names to get tokens from the query parameters
	// of an HTTP request.
	//
	// If multiple keys were given, all the corresponding query
	// values will be treated as candidate tokens. And we will verify each of
	// them until we got a valid one.
	//
	// Priority: from_query > from_header > from_cookies.
	FromQuery []string `json:"from_query"`

	// FromHeader works like FromQuery. But defines a list of names to get
	// tokens from the HTTP header.
	FromHeader []string `json:"from_header"`

	// FromCookie works like FromQuery. But defines a list of names to get tokens
	// from the HTTP cookies.
	FromCookies []string `json:"from_cookies"`

	// IssuerWhitelist defines a list of issuers. A non-empty list turns on "iss
	// verification": the "iss" claim must exist in the given JWT payload. And
	// the value of the "iss" claim must be on the whitelist in order to pass
	// the verification.
	IssuerWhitelist []string `json:"issuer_whitelist"`

	// AudienceWhitelist defines a list of audiences. A non-empty list turns on
	// "aud verification": the "aud" claim must exist in the given JWT payload.
	// The verification will pass as long as one of the "aud" values is on the
	// whitelist.
	AudienceWhitelist []string `json:"audience_whitelist"`

	// UserClaims defines a list of names to find the ID of the authenticated user.
	//
	// By default, this config will be set to []string{"sub"}.
	//
	// If multiple names were given, we will use the first non-empty value of the key
	// in the JWT payload as the ID of the authenticated user. i.e. The placeholder
	// {http.auth.user.id} will be set to the ID.
	//
	// For example, []string{"uid", "username"} will set "eva" as the final user ID
	// from JWT payload: { "username": "eva"  }.
	//
	// If no non-empty values found, leaves it unauthenticated.
	UserClaims []string `json:"user_claims"`

	// MetaClaims defines a map to populate {http.auth.user.*} metadata placeholders.
	// The key is the claim in the JWT payload, the value is the placeholder name.
	// e.g. {"IsAdmin": "is_admin"} can populate {http.auth.user.is_admin} with
	// the value of `IsAdmin` in the JWT payload if found, otherwise "".
	//
	// NOTE: The name in the placeholder should be adhere to Caddy conventions
	// (snake_casing).
	//
	// Caddyfile:
	// Use syntax `<claim>[-> <placeholder>]` to define a map item. The placeholder is
	// optional, if not specified, use the same name as the claim.
	// e.g.
	//
	//     meta_claims "IsAdmin -> is_admin" "group"
	//
	// is equal to {"IsAdmin": "is_admin", "group": "group"}.
	//
	// Since v0.6.0, nested claim path is also supported, e.g.
	// For the following JWT payload:
	//
	//     { ..., "user_info": { "role": "admin" }}
	//
	// If you want to populate {http.auth.user.role} with "admin", you can use
	//
	//     meta_claims "user_info.role -> role"
	//
	// Use dot notation to access nested claims.
	MetaClaims map[string]string `json:"meta_claims"`
	// contains filtered or unexported fields
}

JWTAuth facilitates JWT (JSON Web Token) authentication.

func (*JWTAuth) Authenticate

func (ja *JWTAuth) Authenticate(rw http.ResponseWriter, r *http.Request) (User, bool, error)

Authenticate validates the JWT in the request and returns the user, if valid.

func (JWTAuth) CaddyModule

func (JWTAuth) CaddyModule() caddy.ModuleInfo

CaddyModule implements caddy.Module interface.

func (*JWTAuth) Provision

func (ja *JWTAuth) Provision(ctx caddy.Context) error

Provision implements caddy.Provisioner interface.

func (*JWTAuth) Validate

func (ja *JWTAuth) Validate() error

Validate implements caddy.Validator interface.

type MapClaims

type MapClaims = jwt.MapClaims

type Token

type Token = jwt.Token

type User

type User = caddyauth.User

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL