Manually testing APIs using Client Credentials and bearer tokens with REST Client for Visual Studio Code

Johan Grønstad

The REST Client for Visual Studio Code is an excellent tool for testing HTTP based endpoints. In my opinion it's one of the smoothest ways to test any endpoint behind an HTTP interface.

But there are some use cases where Postman felt like it had a somewhat less finicky workflow, especially when calling an API requiring authentication more complicated than Basic.

If you already use REST Client and know how to use variables, skip to the next part where I show how you can utilize them for a multistep flow using request variables.

If you are not familiar with REST Client and would like to learn more before continuing, check out the documentation.

There are several workflows you could use to call an API requiring a bearer token. From worst to icky you would have:

  1. Logging into the website using Chrome, opening up the Dev tools and manually copying the Bearer token from a response. Then pasting it directly into the request you are about to send using REST Client.
  2. ... several variations of this until you arrive at
  3. Logging into the website using Chrome, opening up the Dev tools and manually copying the Bearer token from a response. Then creating an REST Client environment variable the request you are about to trigger reference.

The last one would allow you to call the API from all .http files referencing the Bearer token until it expires, requiring you to repeat the process for a fresh new token.

It's almost sane, since you're not actually doing any changes to the .http file, which in turn reduces churn and conflicts in version control.

Let's assume all of these workflows are insane, if even possible with the authentication flows configured for your client and API.

So how would you solve this by only using the REST Client (and avoiding churn and conflicts in source control)?

The naive way to solve it is inspired by the last workflow, but instead of using Chrome you'll use REST Client:

You would have this section in your settings file:

"rest-client.environmentVariables": {
    "local": {
        "identityAuthority": "https://localhost:5000/connect/token",
        "baseUrl": "localhost:5001"
        "credential": "Basic dXNlcm5hbWU6c2VjcmV0",
        "token": ""
    }
}

WARNING

The credentials are not in any way encrypted. This is just basic base64 encoding of username:secret. This would only be kind of safe if you are exclusivly running this on your local machine with a unique username and password combination blacklisted in any other environment the API is running in.

Continued

Next you would need a request to the identity server {{identityAuthority}}:

POST {{identityAuthority}} HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: {{credential}}

grant_type=client_credentials&scope=example.scope&client_id=myappid

Executing this request gives you a response containing the token required for requests to the API. Avoiding file variables you'd paste it into the {{token}} variable in the settings file, allowing this request to work as expected:

GET https://{baseUrl}/api/endpoint HTTP/1.1
Authorization: Bearer {{token}}

Next part

Funnily enough when I tried to find a sane workflow for this using the REST Client for Visual Studio Code I eventually found this pull request: Provide possibility to extract values from response

As you might know @cbrevik is actually my colleague Christian Brevik, and there is a slight chance that he might have mentioned this exact pull request on Slack at some point earlier this year 🙃.

But I digress.

This pull request is actually the key for a super smooth workflow, that in my opinion is even better than what Postman delivers.

The changes between the last example and this one are small, but very important. It'll be easy to notice now that we have looked at the previous versions:

# @name login
POST {{identityAuthority}} HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: {{credential}}

grant_type=client_credentials&scope=example.scope&client_id=myappid

Did you notice it?

Let's use it when calling the API. Add the following to the same .http file:

###
GET https://{baseUrl}/api/endpoint HTTP/1.1
Authorization: Bearer {{login.response.body.access_token}}

That's it. As long as you first trigger the request to the {{identityAuthority}}, you can now call the API endpoint within that .http file without doing anything else.

You'll have to refresh the token by triggering the authentication when the previous one expires and when changing .http file you're making requests from. But that's it.

So what did we do here? By using request variables we where able to pick the access token returned in the first request as part of the Authorization header in the request to the API endpoint.

We did that by adding the @name login variable to the first request and then referencing it by adding {{login.response.body.access_token}} to the second request in the .http file.

Easy peasy.