JWT Token V1 REST APIs
The JWT token REST APIs let a client exchange its credentials for a pair of JSON Web Tokens and then access the Kura REST APIs with a bearer token, without sending the identity password or keeping a session cookie on every request. They are suited to scripts, backend services and non-browser clients.
A token pair is made of:
- an access token: sent as
Authorization: Bearer <token>to access any REST API. It is short lived and cannot be revoked. - a refresh token: exchanged once at POST/refresh for a new token pair. It is never accepted as an access token.
Prerequisites
- Configure a JWT Issuing Service and a JWT Verification Service as described in JWT Services. The verification trust store must contain the certificate of the signing key and, if Trusted Issuers is set, it must include the Issuer of the issuing service.
- In the REST Service configuration set JWT Authentication Enabled to true. If several issuing or verification services are available, select them with Token Issuing Service Target and Token Verification Service Target, for example
(kura.service.pid=org.eclipse.kura.core.token.jwt.issuer.JwtIssuingService).
While JWT authentication is disabled, both endpoints return 404 and bearer tokens are not accepted.
Workflow
- Call POST/issue authenticating with any other enabled method: BASIC credentials, a session (with the
X-XSRF-Tokenheader, see Session V1 REST APIs) or a client certificate. A caller authenticated with a JWT access token is refused, so a leaked access token cannot be used to obtain new tokens. - Access the REST APIs with the header
Authorization: Bearer <accessToken>. - Before the access token expires, or when a request fails with 401, call POST/refresh with the refresh token. Replace both stored tokens with the returned ones and discard the used refresh token: exchanging it again revokes all the refresh tokens obtained since step 1.
- If the refresh fails with 401, the refresh token is expired, revoked or no longer valid: go back to step 1.
Example with curl
# 1. issue a token pair (BASIC authentication, requires Basic Authentication Enabled)
curl -k -X POST -u "$KURA_USER:$KURA_PASS" https://$ADDRESS/services/token/jwt/v1/issue
{
"tokenType": "Bearer",
"accessToken": "eyJraWQiOi...",
"accessTokenExpiresInSeconds": 60,
"refreshToken": "eyJraWQiOi...",
"refreshTokenExpiresInSeconds": 900
}
# 2. access a resource
curl -k -H "Authorization: Bearer $ACCESS_TOKEN" https://$ADDRESS/services/$RESOURCE_PATH
# 3. refresh: the body is the bare refresh token, no other credentials are needed
curl -k -X POST -H 'Content-Type: text/plain' --data "$REFRESH_TOKEN" \
https://$ADDRESS/services/token/jwt/v1/refresh
Behavior
- Authorization: tokens carry only the identity name. Permissions are read from the identity on every request, so permission changes apply immediately and a token never grants more than the identity currently has. No permission is needed to call the token endpoints.
- Identity checks: issuing, refreshing and every bearer request fail if the identity no longer exists or must change its password.
- Revocation: access tokens cannot be revoked. Refresh tokens are revoked by token family on reuse, password change and identity deletion, see below. To cut off a client, delete the identity, force a password change, disable JWT authentication, or replace the signing key / trusted certificates.
- Lifetimes: set by JWT Access Token Duration and JWT Refresh Token Duration, silently capped by the Maximum Token Lifetime of the issuing service. The
...ExpiresInSecondsfields report the effective values. Since each refresh token works once, the refresh token duration is the maximum inactivity time of a client. - Refresh token rotation and reuse detection: each POST/issue starts a new token family, and every successful refresh consumes the presented refresh token and returns the next one of the same family. Presenting a refresh token that was already exchanged revokes its whole family: that refresh and every later refresh with any token of the family fail with 401, and the client must call POST/issue again. Other families of the same identity are not affected, and access tokens already issued stay valid until they expire. Serialize refreshes in the client: two concurrent refreshes with the same token revoke the family.
- Password change and identity deletion: all the token families of an identity are revoked when its password changes or when it is deleted. Each family is revoked at its next refresh, which fails with 401, so the revocation is missed if, before that refresh, the password is changed back to the previous one or the identity is re-created with the same password (or again without one). After a password change, access tokens already issued stay valid until they expire.
- Restarts: token families are tracked in memory until their latest refresh token expires plus JWT Refresh Token Family Retention, which must be greater than or equal to the Clock Skew Tolerance of the verification service. After a Kura restart all refresh tokens are refused, and clients must call POST/issue again.
- Failed issuing: if a new pair cannot be issued during a refresh (500 or 503), the refresh token is not consumed and can be retried.
- External tokens: access tokens trusted by the verification service are accepted even if issued outside Kura, provided
subis an existing Kura identity andaudcontains/token/jwt/v1/access. POST/refresh only accepts refresh tokens issued by this Kura instance. - Caching: token responses carry
Cache-Control: no-storeandPragma: no-cache. Store tokens as credentials: never log them or put them in URLs. - Provider order: bearer authentication is attempted after the certificate, BASIC and session providers. The Allowed Ports restriction applies as for any other REST API.
Reference
- JWT Token V1 REST APIs
- Prerequisites
- Workflow
- Behavior
- Reference
- Request definitions
- JSON definitions
Request definitions
POST/issue
- REST API path : /services/token/jwt/v1/issue
- description : Issues a new token pair for the identity that authenticated the request. Authentication with a JWT access token is not accepted.
- responses :
- 200
- description : Request succeeded.
- response body :
- 401
- description : The request is not authenticated, it is authenticated with a JWT access token, or the identity does not exist.
- 403
- description : The identity must change its password.
- 404
- description : JWT authentication is disabled or no token issuing service matches the configured target.
- 500
- description : Token issuing failed, for example the signing key is not available.
- 503
- description : The token issuing service is temporarily unavailable.
- 200
POST/refresh
- REST API path : /services/token/jwt/v1/refresh
- description : Exchanges a refresh token for a new token pair. No other authentication is needed. The request body must be the refresh token as
text/plain; surrounding whitespace is ignored and the body is limited to 8 KiB. - responses :
- 200
- description : Request succeeded, the exchanged refresh token can no longer be used: exchanging it again revokes its token family.
- response body :
- 400
- description : The request body is empty.
- 401
- description : The refresh token is invalid, expired, already used, revoked, not issued by this Kura instance since its last restart, or not a refresh token, or its identity does not exist or changed its password since POST/issue. An already used refresh token, a deleted identity or a changed password also revokes the token family.
- 403
- description : The identity must change its password.
- 404
- description : JWT authentication is disabled or no token issuing or verification service matches the configured targets.
- 413
- description : The request body is larger than 8 KiB.
- 500
- description : Token issuing failed. The refresh token is not consumed.
- 503
- description : The token issuing or verification service is temporarily unavailable. The refresh token is not consumed.
- 200
JSON definitions
TokenPair
A newly issued access and refresh token pair.
Properties:
- tokenType:
stringAlwaysBearer. - accessToken:
stringThe access token, to be sent in theAuthorization: Bearerheader. - accessTokenExpiresInSeconds:
numberEffective lifetime of the access token, in seconds. - refreshToken:
stringThe refresh token, to be sent to POST/refresh. - refreshTokenExpiresInSeconds:
numberEffective lifetime of the refresh token, in seconds.