github.com/BTBurke/caddy-jwt@v3.7.1+incompatible/README.md (about)

     1  ## JWT
     2  
     3  [![Build Status](https://travis-ci.org/BTBurke/caddy-jwt.svg?branch=master)](https://travis-ci.org/BTBurke/caddy-jwt)
     4  
     5  **Authorization Middleware for Caddy**
     6  
     7  This middleware implements an authorization layer for [Caddy](https://caddyserver.com) based on JSON Web Tokens (JWT).  You can learn more about using JWT in your application at [jwt.io](https://jwt.io).
     8  
     9  ### Basic Syntax
    10  
    11  ```
    12  jwt [path]
    13  ```
    14  
    15  By default every resource under path will be secured using JWT validation.  To specify a list of resources that need to be secured, use multiple declarations:
    16  
    17  ```
    18  jwt [path1]
    19  jwt [path2]
    20  ```
    21  
    22  > **Important** You must set the secret used to construct your token in an environment variable named `JWT_SECRET`(HMAC) *or* `JWT_PUBLIC_KEY`(RSA or ECDSA).  Otherwise, your tokens will silently fail validation.  Caddy will start without this value set, but it must be present at the time of the request for the signature to be validated.
    23  
    24  ### Advanced Syntax
    25  
    26  You can optionally use claim information to further control access to your routes.  In a `jwt` block you can specify rules to allow or deny access based on the value of a claim.
    27  If the claim is a json array of strings, the allow and deny directives will check if the array contains the specified string value.  An allow or deny rule will be valid if any value in the array is a match.
    28  
    29  ```
    30  jwt {
    31     path [path]
    32     redirect [location]
    33     allow [claim] [value]
    34     deny [claim] [value]
    35  }
    36  ```
    37  
    38  To authorize access based on a claim, use the `allow` syntax.  To deny access, use the `deny` keyword.  You can use multiple keywords to achieve complex access rules.  If any `allow` access rule returns true, access will be allowed.  If a `deny` rule is true, access will be denied.  Deny rules will allow any other value for that claim.   
    39  
    40    For example, suppose you have a token with `user: someone` and `role: member`.  If you have the following access block:
    41  
    42  ```
    43  jwt {
    44     path /protected
    45     deny role member
    46     allow user someone
    47  }
    48  ```
    49  
    50  The middleware will deny everyone with `role: member` but will allow the specific user named `someone`.  A different user with a `role: admin` or `role: foo` would be allowed because the deny rule will allow anyone that doesn't have role member.
    51  
    52  If the optional `redirect` is set, the middleware will send a redirect to the supplied location (HTTP 303) instead of an access denied code, if the access is denied.
    53  
    54  ### Ways of passing a token for validation
    55  
    56  There are three ways to pass the token for validation: (1) in the `Authorization` header, (2) as a cookie, and (3) as a URL query parameter.  The middleware will **by default** look in those places in the order listed and return `401` if it can't find any token.
    57  
    58  | Method               | Format                          |
    59  | -------------------- | ------------------------------- |
    60  | Authorization Header | `Authorization: Bearer <token>` |
    61  | Cookie               | `"jwt_token": <token>`          |
    62  | URL Query Parameter  | `/protected?token=<token>`      |
    63  
    64  It is possible to customize what token sources should be used via the `token_source` rule. If at one or more `token_source` rules are specified, they will be used instead of the default in the given order. For example, to
    65  do the same validation as default, but with the different header, cookie and query param names, the user could use the following snippet:
    66  
    67  ```
    68  jwt {
    69     ...
    70     token_source header my_header_type
    71     token_source cookie my_cookie_name
    72     token_source query_param my_param_name
    73  }
    74  ```
    75  
    76  #### Note about `Authorization` header
    77  
    78  The optional header type is for Bearer tokens by other names, like `ApplePass` used by Apple PassKit. If not provided, it defaults to `Bearer` as defined in RFC6750. This does not support more complex schemes that require a challenge/response.
    79  
    80  ### Constructing a valid token
    81  
    82  JWTs consist of three parts: header, claims, and signature.  To properly construct a JWT, it's recommended that you use a JWT library appropriate for your language.  At a minimum, this authorization middleware expects the following fields to be present:
    83  
    84  ##### Header
    85  
    86  ```json
    87  {
    88  "typ": "JWT",
    89  "alg": "HS256|HS384|HS512|RS256|RS384|RS512|ES256|ES384|ES512"
    90  }
    91  ```
    92  
    93  ##### Claims
    94  
    95  If you want to limit the validity of your tokens to a certain time period, use the "exp" field to declare the expiry time of your token.  This time should be a Unix timestamp in integer format.
    96  ```json
    97  {
    98  "exp": 1460192076
    99  }
   100  ```
   101  
   102  ### Acting on claims in the token
   103  
   104  You can of course add extra claims in the claim section.  Once the token is validated, the claims you include will be passed as headers to a downstream resource.  Since the token has been validated by Caddy, you can be assured that these headers represent valid claims from your token.  For example, if you include the following claims in your token:
   105  
   106  ```json
   107  {
   108    "user": "test",
   109    "role": "admin",
   110    "logins": 10,
   111    "groups": ["user", "operator"],
   112    "data": {
   113      "payload": "something"
   114    }
   115  }
   116  ```
   117  
   118  The following headers will be added to the request that is proxied to your application:
   119  
   120  ```
   121  Token-Claim-User: test
   122  Token-Claim-Role: admin
   123  Token-Claim-Logins: 10
   124  Token-Claim-Groups: user,operator
   125  Token-Claim-Data.payload: something
   126  ```
   127  
   128  Token claims will always be converted to a string.  If you expect your claim to be another type, remember to convert it back before you use it.  Nested JSON objects will be flattened.  In the example above, you can see that the nested `payload` field is flattened to `data.payload`.
   129  
   130  All request headers with the prefix `Token-Claim-` are stripped from the request before being forwarded upstream, so users can't spoof them.
   131  
   132  Claims with special characters that aren't allowed in HTTP headers will be URL escaped.  For example, Auth0 requires that claims be namespaced with the full URL such as
   133  
   134  ```json
   135  {
   136    "http://example.com/user": "test"
   137  }
   138  ```
   139  
   140  The URL escaping will lead to some ugly headers like
   141  
   142  ```
   143  Token-Claim-Http:%2F%2Fexample.com%2Fuser: test
   144  ```
   145  
   146  If you only care about the last section of the path, you can use the `strip_header` directive to strip everything before the last portion of the path.
   147  
   148  ```
   149  jwt {
   150    path /
   151    strip_header
   152  }
   153  ```
   154  
   155  When combined with the claims above, it will result in a header:
   156  
   157  ```
   158  Token-Claim-User: test
   159  ```
   160  
   161  ### Allowing Public Access to Certain Paths
   162  
   163  In some cases, you may want to allow public access to a particular path without a valid token.  For example, you may want to protect all your routes except access to the `/login` path.  You can do that with the `except` directive.
   164  
   165  ```
   166  jwt {
   167    path /
   168    except /login
   169  }
   170  ```
   171  
   172  Every path that begins with `/login` will be excepted from the JWT token requirement.  All other paths will be protected.  In the case that you set your path to the root as in the example above, you also might want to allow access to the so-called naked or root domain while protecting everything else.  You can use the directive `allowroot` which will allow access to the naked domain.  For example, if you have the following config block:
   173  
   174  ```
   175  jwt {
   176    path /
   177    except /login
   178    allowroot
   179  }
   180  ```
   181  
   182  Requests to `https://example.com/login` and `https://example.com/` will both be allowed without a valid token.  Any other path will require a valid token.
   183  
   184  ### Allowing Public Access Regardless of Token
   185  
   186  In some cases, a page should be accessible whether a valid token is present or not. An example might be the Github home page or a public repository, which should be visible even to logged-out users. In those cases, you would want to parse any valid token that might be present and pass the claims through to the application, leaving it to the application to decide whether the user has access. You can use the directive `passthrough` for this:
   187  
   188  ```
   189  jwt {
   190    path /
   191    passthrough
   192  }
   193  ```
   194  
   195  It should be noted that `passthrough` will *always* allow access on the path provided, regardless of whether a token is present or valid, and regardless of `allow`/`deny` directives. The application would be responsible for acting on the parsed claims.
   196  
   197  ### Specifying Keys for Use in Validating Tokens
   198  
   199  There are two ways to specify key material used in validating tokens.  If you run Caddy in a container or via an init system like Systemd, you can directly specify your keys using the environment variables `JWT_SECRET` for HMAC or `JWT_PUBLIC_KEY` for RSA or ECDSA (PEM-encoded public key).  You cannot use both at the same time because it would open up a known security hole in the JWT specification.  When you run multiple sites, all would have to use the same keys to validate tokens.
   200  
   201  When you run multiple sites from one Caddyfile, you can specify the location of a file that contains your PEM-encoded public key or your HMAC secret.  Once again, you cannot use both for the same site because it would cause a security hole.  However, you can use different methods on different sites because the configurations are independent.
   202  
   203  For RSA or ECDSA tokens:
   204  
   205  ```
   206  jwt {
   207    path /
   208    publickey /path/to/key.pem
   209  } 
   210  ```
   211  
   212  For HMAC:
   213  
   214  ```
   215  jwt {
   216    path /
   217    secret /path/to/secret.txt
   218  }
   219  ```
   220  
   221  When you store your key material in a file, this middleware will cache the result and use the modification time on the file to determine if the secret has changed since the last request.  This should allow you to rotate your keys or invalidate tokens by writing a new key to the file without worrying about possible file locking problems (although you should still check that your write succeeded before issuing tokens with your new key.)
   222  
   223  If you have multiple public keys or secrets that should be considered valid, use multiple declarations to the keys or secrets in different files.  Authorization will be allowed if any of the keys validate the token.
   224  
   225  ```
   226  jwt {
   227    path /
   228    publickey /path/to/key1.pem
   229    publickey /path/to/key2.pem
   230  }
   231  ```
   232  
   233  ### Possible Return Status Codes
   234  
   235  | Code | Reason |
   236  | ---- | ------ |
   237  | 401 | Unauthorized - no token, token failed validation, token is expired |
   238  | 403 | Forbidden - Token is valid but denied because of an ALLOW or DENY rule |
   239  | 303 | A 401 or 403 was returned and the redirect is enabled.  This takes precedence over a 401 or 403 status. |
   240  
   241  
   242  ### Caveats
   243  
   244  JWT validation depends only on validating the correct signature and that the token is unexpired.  You can also set the `nbf` field to prevent validation before a certain timestamp.  Other fields in the specification, such as `aud`, `iss`, `sub`, `iat`, and `jti` will not affect the validation step.