Vladimir Dyuzhev
MockMotor Creator
Mocking Services with JWT
MockMotor natively supports JWT. You can generate, parse and verify JWT tokens with minimum efforts.
You may also be interested in a practical guide on how to build a complete JWT Auth service on top of MockMotor.
What is JWT?
JWT is a simple way to support authorization and identification in web services.
After decoding the token provided with a request, a service can say if this request came from a consumer that has a right to perform this call. This is the authorization function.
It can also, if encoded in the token, see what is that consumer’s user id (or other credentials). This is the identification function.
Before JWT, many standards aimed to perform the same function, but they are bulky and inconvenient to use. (See SAML, for example.) JWT, on the other hand, is compact and can be built from basic JSON objects.
How JWT Works?
Long story short: a client gets a token from an authentication server. The token is actually an encoded JSON object. With this token at hand, the client can call any service that supports JWT and trusts the original authentication service. Eventually, the token expires, and the client has to get a new one.
If we go step by step, it is like this:
1 The client calls the authentication service, providing whatever credentials (username/password or whatnot) they have.
2 The authentication service generates a JWT token. If required, the user identity information is included in the token payload part.
3 The token is signed with either a secret password or a key pair.
4 The authentication service provides the token back to the client.
JWT specification doesn’t say how the clients should obtain the token, and so the designs of the authentication service can be very different. Only the JWT format is standardized. JWT authentication response can, for example, look like this:
HTTP/1.1 200 OK
Date: Mon, 21 Jan 2019 02:41:33 GMT
Content-Type: application/json; charset=UTF-8
{
"token": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiJqb2huLmRvZSJ9.CuScq77_iCP4XsYGCMgGnQiATOmQwu_rR1LEB2Pcd_I"
}
5 The client includes the token into every subsequent service call. The token is placed into the HTTP Authorization
header.
A request to a service that requires JWT authentication can look like this:
POST https://localhost:7081/ETLWorks/plugins/flows/rest/v1/flows/flow-name/ProcessOrders/run/ HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiJqb2huLmRvZSJ9.CuScq77_iCP4XsYGCMgGnQiATOmQwu_rR1LEB2Pcd_I
Host: localhost:7081
{
"order":"LARGEST_FIRST"
}
6 The web service receives a token and verifies it. The token must have a valid signature and shouldn’t be expired or not active yet.
7 If required, the service extracts the caller identity information from the token payload part.
Note the Authorization
header with Bearer
and the encoded token value eyJ0eXAiOiJKV1QiLCJhbGciOiJIUz...
.
For those more SDS-inclined, here is a JWT authentication and usage diagram:
How is JWT Used?
Only your imagination is a limit. However, here are a few most common scenarios (in my experience, anyway):
Use Case 1: Only Authorization
In the simplest case, the target service is not concerned with the content of the token and only uses it as proof of access rights (i.e. authorization).
That is, the client performs the token verification, but doesn’t use any value from the token’s header or payload for its functions. All the information required for handling the request is in the request body itself.
Use Case 2: Identification
In a more complex scenario, the target service performs the token verification for access rights check, but also needs to extract some data from the token to execute the request.
Since the token data are typically related to the logged-in user, the extracted data are used for identification.
For instance, a service call that modifies a customer profile may need, for audit purposes, to log who has altered the profile. The token then may contain a user id of the person who initiated the request. The service reads the user id from the token and saves it into the audit record.
Since the token is signed, it is next to impossible to forge someone else’s id into the token.
JWT Support in MockMotor
MockMotor has native support for JWT in Javascript-based responses.
A mock service can generate a token, like below:
var header = {
"alg": "HS256",
};
var payload = {
"userid": "john.doe"
};
var token = JWT.encode(header,payload,"qwerty");
output = {"token":token};
read the token claims:
var userid = JWT.payload.userid;
or verity the token, as here:
if( JWT.decode(JWT.token,"hexodiagonal123").error != null ) {
// handle the token error
...
}
For more details on the available API, check out the documentation page.
How to Mock a JWT-Protected Service
There are a few approaches to mock services protected with JWT. They range in required efforts. Which one to choose is your call, but if you have time, I suggest you always to implement the complete JWT solution (Generate and Verify below).
With the full solution, you don’t have to worry that the implementation changes into decoding the token on the client or calling JWT services outside of your mock environment, and so begins to fail with mysterious errors.
I’ll list the approaches from the simplest to the most complex:
(Easiest) Ignore JWT Token
Do nothing.
Many services that are protected by JWT don’t read the values (“claims”) from the token.
When such services are mocked, they don’t need to handle JWT at all - the mock service ignores the Authorization
header.
Hence you don’t have to do anything in the mocks. The client sends the token, and the mocks ignore the token.
In this sense, all mocks have basic JWT support by default.
(Easy) Fake JWT Token
If neither mock services nor clients decode the token, but you also need to mock the JWT authentication service itself,
you can provide a random string as a token in the authentication response.
The clients don’t try to parse that random string, sending it in the Authorization: Bearer
header as-is.
Here is a dummy authentication service that listens on URI /authenticate/dummy
, responds to POST and returns a JSON with a token
value which is just a random UUID:
The client request may look like below. The mock services ignore the invalid JWT in the Authorization
header, so the request works anyway.
POST https://localhost:7081/ExamplesForBlog/JWT/execute/dummy HTTP/1.1
Content-Type: application/json
Authorization: Bearer fb2f6a8c-f00c-4a26-b304-6b2f7bed07a0
Host: localhost:7081
{
"name":"john.doe"
}
Since mock services ignore the Authentication
header, the system works - with the minimum efforts.
(Moderate) Generate Proper JWT
Sometimes mock services need to read data from the token.
For instance, JWT payload may contain a userid field, which mock services use to select the mock account. Or the client may decode JWT to consult its expiration time.
Then, in the mock authentication service, you have to generate the JWT token correctly.
Good news it is not hard! You need to use the JWT.encode()
function available in MockMotor:
var header = {
"alg": "HS256",
"typ": "JWT"
};
var payload = {
"login": input.login,
};
var token = JWT.encode(header,payload,"password123");
output = {
"token":token
};
JWT token consists of two parts - the header and the payload. You define the signature algorithm (alg
) in the header, and
any data that are useful for services in the payload, and then encode them both with JWT.encode
. You need to provide
a secret (password) as the third parameter.
The result is the JWT (as a string), which you can return to the caller the way it’s expected from this authentication service.
For example, in the code above the result is { "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJ..." }
(Fully Functional) Generate and Verify JWT
Once we generated the correct JWT with JWT.encode
, there is only one step left to the full-functioning JWT security system: we need to verify the
incoming JWTs.
Why would we need to do that in mocks? One important scenario is to test the functionality or performance of code when a JWT expires. Typical code would have to handle this case gracefully, obtaining a new JWT from the authorization service and retrying the request; showing any errors to the user is a bad taste.
How can we do it?
Add Expiration Claim
First, we need to add the expiration timestamp to the token when it is generated.
In JWT, the expiration is added to the payload as exp
claim.
Here the exp
is set 10s in the future; in other words, in 10s the token will expire and won’t pass verification anymore:
Verify the Token
Now we need to verify the token when it is sent in as in Authorization
header.
We pass the token to the JWT.decode
function, providing our secret (password).
If the token fails validation for any reason (including the expiration), the result will have the error message in the error
field.
That field is assigned to the jwtError
variable.
Then we check if the jwtError
is not null (i.e. some error has happened) and return an error payload. Otherwise, we return the normal payload:
The jwtError
variable is later available in the HTTP Status Code
field as well, so we use it to set the status to 401
if there is an error:
Verify Token Once for Many Responses
Usually, you have multiple responses that are under JWT authorization. It is annoying (and not efficient) to verify the token in each response separately. There is a better way.
Have a dedicated “Verify Token” response and place it first in the responses list. That response returns HTTP 401 if the token is not valid. If the token is valid, the response doesn’t match, and MockMotor proceeds to check the next response.
The trick then is to make the Verify Token
response matching when the token is invalid. This is pretty easy. You need:
1 Match Any
HTTP method. We verify tokens for all methods.
2 Do not use the Operation
match - we verify all URLs.
3 Make Script
result in true
if the verification has failed.
Just as in the previous case, the JWT.decode
function provides the error in the error
field if the token is invalid. If we have
anything in this field, the response matches:
Then, in all other mocks, you should assume the token is valid because it has been verified already.
Example Projects
For your reference, the demo installation contains a couple of services that illustrate working with JWT.
JWT
A service called JWT has responses that generate JWT token (fake and real) and respond to a business call protected with JWT token (ignoring the token or verifying it).
ETLWorks
Another service, ETLWorks, simulates a real-world service from a cloud-integration provider ETLWorks.
That mock service contains its own authentication URL that generates valid JWT tokens, a JWT Verify response that protects all responses below it and a couple of business responses that use the data from the token payload.
As such, it is a ready-to-use framework to build your own JWT mock services.