docs-site/content/docs/how-to/jwt-locations.md
+++ title = "Configure Where Loco Looks for the JWT" description = "Set the JWT token location — Bearer header, query parameter, or cookie — as a single location or a fallback list." date = 2021-05-01T18:10:00+00:00 updated = 2021-05-01T18:10:00+00:00 draft = false weight = 42 sort_by = "weight" template = "docs/page.html"
[extra] lead = "" toc = true top = false +++
Goal: control where the JWT and JWTWithUser<T> extractors look for the token in an incoming request — the Authorization header (default), a query string parameter, a cookie, or a fallback list of several.
This setting is auth.jwt.location in your config file. It applies only to the JWT extractors (auth::JWT, auth::JWTWithUser<T>); it has no effect on auth::ApiToken<T>, which always reads a Bearer header regardless of this config — see Protect a route with an API key.
If you haven't set up JWT auth yet, start with Protect a route with JWT; this page only covers the location key.
If you omit location entirely, Loco reads the token from the Authorization: Bearer <token> header:
auth:
jwt:
secret: "<%= get_env(name='JWT_SECRET') %>"
expiration: 604800
# location omitted => Bearer header
Set location to one map with a from: tag. The three variants:
Bearer header (equivalent to the default, spelled out explicitly):
auth:
jwt:
location:
from: Bearer
secret: "<%= get_env(name='JWT_SECRET') %>"
expiration: 604800
Query parameter — reads a named query-string value, e.g. for links that can't carry custom headers (email verification links, WebSocket handshakes):
auth:
jwt:
location:
from: Query
name: token
secret: "<%= get_env(name='JWT_SECRET') %>"
expiration: 604800
curl 'http://127.0.0.1:5150/api/protected?token=<TOKEN>'
Cookie — reads a named cookie, e.g. for server-rendered apps using session-style cookies:
auth:
jwt:
location:
from: Cookie
name: auth_token
secret: "<%= get_env(name='JWT_SECRET') %>"
expiration: 604800
curl 'http://127.0.0.1:5150/api/protected' --cookie 'auth_token=<TOKEN>'
Set location to a YAML list instead of a single map. Loco tries each location in the order listed and uses the first one that yields a token — useful when, say, browser clients send a cookie but API clients send a Bearer header:
auth:
jwt:
location:
- from: Cookie
name: auth_token
- from: Query
name: token
- from: Bearer
secret: "<%= get_env(name='JWT_SECRET') %>"
expiration: 604800
With this config, a request is accepted if it carries a valid token in the auth_token cookie, or (if that's absent) a token query parameter, or (if both are absent) an Authorization: Bearer header — checked in that order. If none of the configured locations yields a token, the request is rejected with 401 Unauthorized.
For a Multiple config like the one above, confirm each location independently:
# via cookie
curl 'http://127.0.0.1:5150/api/protected' --cookie 'auth_token=<TOKEN>'
# via query parameter
curl 'http://127.0.0.1:5150/api/protected?token=<TOKEN>'
# via Bearer header
curl 'http://127.0.0.1:5150/api/protected' --header 'Authorization: Bearer <TOKEN>'
Each should succeed independently; a request with no token in any of the three should return 401 Unauthorized.
auth.jwt key table, including JWTLocation/JWTLocationConfig shapes.