Skip to content

JWT Explanation

Raymond King edited this page Apr 9, 2018 · 8 revisions

JWT is an industry standard RFC 7519 method for securing backend resources. The client has to request a JWT using an authentication username and password. The backend service will return a token which can be used with an HttpHeader to request access to backend resources. The token does have an expiry time and must be refreshed when it's expiry time has been reached.

To get a better understand of JWT please view: https://jwt.io/

Normal Workflow

Here is an example.

Authentication

This is a request that can be sent to the authentication end point.

POST /authenticate/login
Content-Type: application/json
Cookie:JSESSIONID=E357B3D0DDF4CEF464C62911CE5AC32C
{
"username":"admin",
"password":"openpcm"
}

Here is the response from backend service

Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
date: Thu, 08 Mar 2018 06:41:58 GMT
{
  "user": {
    "id": 1,
    "username": "admin",
    "mrn": null,
    "firstName": "Admin",
    "lastName": "User",
    "middleName": null,
    "maidenName": null,
    "gender": null,
    "dateOfBirth": null,
    "email": "openpcm@gmail.com",
    "phoneNumber": null,
    "ssn": null,
    "enabled": true,
    "address": null,
    "attributes": null,
    "roles": [
      {
        "id": 1,
        "name": "ROLE_ADMIN"
      }
    ]
  },
  "token": {
    "access_token": "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcGVucGNtLXNlcnZlciIsInN1YiI6ImFkbWluIiwiYXVkIjoid2ViIiwiaWF0IjoxNTIzMjIxMTA4LCJleHAiOjE1MjMyMjE0MDh9.jDPM6ycdSJosUISQPIOwbAaYdjKUQb5nlvFfS3xaaBh4pSIvYjeL-IrN7uFw4Cw3IxCzVZtLyiqqGZ7323IkSQ",
    "expires_in": 300
  }
}

Token Use for Protected Access

Here we can see the access token that we now can use to make calls to protected resources. You also have access to the user object that is now logged in.

GET /api/v1/role
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcGVucGNtLXNlcnZpY2UiLCJzdWIiOiJhZG1pbiIsImF1ZCI6IndlYiIsImlhdCI6MTUyMDQ5MjI2OCwiZXhwIjoxNTIwNDkyNTY4fQ.3H3E5HuUgrclE-xg1JHxoHecWnOZQF921r7lng_zF13H_BQEqe3jkzOsleUO6blqgd3lZ15FQSSlcwg3eSzmEg

Here is the response since our token is valid:

Content-type: application/json;charset=UTF-8
[{"id":1,"name":"ROLE_ADMIN","authority":"ROLE_ADMIN"},{"id":2,"name":"ROLE_USER","authority":"ROLE_USER"}]

Refreshing Tokens

The tokens inside OpenPCM currently expire every 5 minutes. Once 5 minutes has passed, we can request a new token from the backend server (note if we call refresh with a token that has not expired the backend service will return the same token so there is no damage done by calling refresh too early)

POST /authenticate/refresh
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcGVucGNtLXNlcnZpY2UiLCJzdWIiOiJhZG1pbiIsImF1ZCI6IndlYiIsImlhdCI6MTUyMDQ5MjI2OCwiZXhwIjoxNTIwNDkyNTY4fQ.3H3E5HuUgrclE-xg1JHxoHecWnOZQF921r7lng_zF13H_BQEqe3jkzOsleUO6blqgd3lZ15FQSSlcwg3eSzmEg

The response is:

Content-Type: application/json;charset=UTF-8
{
"access_token": "eyJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJvcGVucGNtLXNlcnZpY2UiLCJzdWIiOiJhZG1pbiIsImF1ZCI6IndlYiIsImlhdCI6MTUyMDQ5MjM0MCwiZXhwIjoxNTIwNDkyNjQwfQ.jt-EAdWWcM_li5ek7XEXxxL1Aee_aKkVQucFMPTo9JC6TDrHV4vdIVjkvBZFzjz5MhrSKHz62TFKIxy4izRoWA",
"expires_in": 300
}

Exception Cases

Unauthorized

If you attempt to make a REST call without a token or without proper role to a protected resource, you will receive a 401 Unauthorized error. Here is the response body:

{
  "timestamp": 1523248869229,
  "status": 401,
  "error": "Unauthorized",
  "message": "Full authentication is required to access this resource",
  "path": "/api/v1/user"
}

Expired

If you attempt to make a REST call with an expired token, Spring will reject the request and will throw a 500 error. You only need to refresh the token if this happens using the above flow. Here is the response body:

{
  "timestamp": 1523248647859,
  "status": 500,
  "error": "Internal Server Error",
  "message": "JWT expired at 2018-04-08T23:37:17-0500. Current time: 2018-04-08T23:37:27-0500",
  "path": "/api/v1/user"
}
Clone this wiki locally