With the release of VMware Cloud Foundation 4.0, all the SDDC Manager APIs use a token-based authentication model for API invocation. The previous VMware Cloud Foundation 3.x releases use basic auth model, which is deprecated in the VCF 4.x releases. This document captures the steps needed to migrate to using token-based authentication while invoking public APIs
Symptoms:
If the customer tries to execute an API by using Basic Authentication in 4.x, the following error will be thrown “Authorization Header is missing or not in correct format”
Example:
curl -k -u ‘username:password’ https://10.0.0.4/v1/users {"status":401,"message":"Authorization Header is missing or not in correct format"}
Not Applicable (Starting from 4.x Release all the public APIs are based on token-based authentication)
Workaround:
API usage in 4.x
All SDDC Manager APIs are secured using token-based authentication.
• As a first step before invocation of any API, an access token has to be obtained using the TOKEN API.
• Invoking the Token API returns a token pair - access token and refresh token.
• To invoke an API, the access token has to be passed in the Authorization header as a Bearer token.
• Access token has limited validity. Validity of the access token is currently 1 hour and of the refresh token is 24 hours.
• Once the access token is expired a Refresh token can be used to renew the access token.
Steps for generating the token and consuming is documented below.
1. GENERATE THE TOKEN USING TOKEN API
Prerequisites :
VCF Credentials
• User created in PSC and associated as an ADMIN , OPERATOR or VIEWER role in VMware Cloud Foundation
• Username
• Password
CURL Request
curl -X POST -H "Content-Type: application/json" -d '{"username": "[email protected]","password": "temp!"}' https://sddcmanagerIp/v1/tokens
Example
Invoke the API with the right credentials. The credentials passed in the payload are of users created in PSC and mapped to either ADMIN, OPERATOR or VIEWER role in VCF.
[root@test-linuxJump ~]# curl -X POST -H "Content-Type: application/json" -d '{"username": "[email protected]","password": "****"}' https://10.0.0.4/v1/tokens | json_pp % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 730 0 662 100 68 710 72 --:--:-- --:--:-- --:--:-- 710 { "accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJhZmI2MjNkZS1kZjIwLTQ1NWEtOWQ3NC1mYzgwZmFjNzM5ZGUiLCJpYXQiOjE1ODIxOTcxODcsInN1YiI6InZjZi1zZWN1cmUtdXNlckB2c3BoZXJlLmxvY2FsIiwiaXNzIjoidmNmLWF1dGgiLCJhdWQiOiJzZGRjLXNlcnZpY2VzIiwibmJmIjoxNTgyMTk3MTg3LCJleHAiOjE1ODIyMDA3ODcsInVzZXIiOiJ2Y2Ytc2VjdXJlLXVzZXJAdnNwaGVyZS5sb2NhbCIsIm5hbWUiOiJ2Y2Ytc2VjdXJlLXVzZXJAdnNwaGVyZS5sb2NhbCIsInNjb3BlIjpbIkJBQ0tVUF9DT05GSUdfUkVBRCIsIkNSRURFTlRJQUxfUkVBRCIsIlVTRVJfV1JJVEUiLCJPVEhFUl9XUklURSIsIkJBQ0tVUF9DT05GSUdfV1JJVEUiLCJPVEhFUl9SRUFEIiwiVVNFUl9SRUFEIiwiQ1JFREVOVElBTF9XUklURSJdfQ._92IFJCQsbRbAWd4PQmBDczWXtuVCWPOsL1ZyCdKEMU", "refreshToken": { "id": "3c6b3c30-####-####-####-########928" } }
2. INVOKE THE API USING THE ACCESS TOKEN
Use the accessToken generated in previous step, and pass this token as Bearer token in Authorization header. Here is the sample API invocation that uses a Bearer Token in Authorization header to list users using VCF Public API
Curl Request
curl -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" https://sddcmanagerIp/v1/example
Example
[root@test-linuxJump ~]# curl -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJhZmI2MjNkZS1kZjIwLTQ1NWEtOWQ3NC1mYzgwZmFjNzM5ZGUiLCJpYXQiOjE1ODIxOTcxODcsInN1YiI6InZjZi1zZWN1cmUtdXNlckB2c3BoZXJlLmxvY2FsIiwiaXNzIjoidmNmLWF1dGgiLCJhdWQiOiJzZGRjLXNlcnZpY2VzIiwibmJmIjoxNTgyMTk3MTg3LCJleHAiOjE1ODIyMDA3ODcsInVzZXIiOiJ2Y2Ytc2VjdXJlLXVzZXJAdnNwaGVyZS5sb2NhbCIsIm5hbWUiOiJ2Y2Ytc2VjdXJlLXVzZXJAdnNwaGVyZS5sb2NhbCIsInNjb3BlIjpbIkJBQ0tVUF9DT05GSUdfUkVBRCIsIkNSRURFTlRJQUxfUkVBRCIsIlVTRVJfV1JJVEUiLCJPVEhFUl9XUklURSIsIkJBQ0tVUF9DT05GSUdfV1JJVEUiLCJPVEhFUl9SRUFEIiwiVVNFUl9SRUFEIiwiQ1JFREVOVElBTF9XUklURSJdfQ._92IFJCQsbRbAWd4PQmBDczWXtuVCWPOsL1ZyCdKEMU" https://10.0.0.4/v1/users | json_pp % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 2149 0 2149 0 0 3446 0 --:--:-- --:--:-- --:--:-- 3449 { "elements" : [ { "domain" : "VSPHERE.LOCAL", "creationTimestamp" : "2020-02-19T13:50:59.783Z", "name" : "[email protected]", "type" : "USER", "id" : "e906b68a-####-####-####-########a1b", "role" : { "id" : "d40632bd-####-####-####-########3c5" } } ] }
3. GENERATE A NEW ACCESS TOKEN USING REFRESH TOKEN IF THE ACCESS TOKEN IS EXPIRED
Refresh tokens are a special type of credential tokens that is used to generate access tokens. This workflow is used when access tokens have expired. They generate a new access token when the current access token either expires or is invalid or to generate additional tokens. Typical expiration time of access token is 1 hour and that of refresh tokens is 1 day
Prerequisites:
The following data is required
Curl Request
curl -X PATCH -H "Content-Type: application/json" -d 'refresh-token' https://sddcmanagerIp/v1/tokens/access-token/refresh
Examples
Example of token getting expired
root@sddc-manager [ ~ ]# curl -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' https://10.0.0.4/v1/sddc-manager -k | jq % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 173 100 173 0 0 2436 0 --:--:-- --:--:-- --:--:-- 2471 { "status": 401, "message": "JWT expired at 2021-03-11T02:27:33Z. Current time: 2021-03-11T02:29:21Z, a difference of 108620 milliseconds. Allowed clock skew: 0 milliseconds." }
Generate new access token using Refresh token
root@sddc-manager [ /home/vcf ]# curl 'https://10.0.0.4/v1/tokens/access-token/refresh' -X PATCH -H 'Content-Type: application/json' -H 'Accept: application/json' -d '"cfd6e2df-####-####-####-########d8a"' -k
{
"eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJhNjg5Njk0YS02Njc1LTQwYzQtYTk1NS03YWE3OWI3NDM3MzciLCJpYXQiOjE2MjQ1Mzc1ODMsInN1YiI6ImFkbWluaXN0cmF0b3JAdnNwaGVyZS5sb2NhbCIsImlzcyI6InZjZi1hdXRoIiwiYXVkIjoic2RkYy1zZXJ2aWNlcyIsIm5iZiI6MTYyNDUzNzU4MywiZXhwIjoxNjI0NTQxMTgzLCJ1c2VyIjoiYWRtaW5pc3RyYXRvckB2c3BoZXJlLmxvY2FsIiwibmFtZSI6ImFkbWluaXN0cmF0b3JAdnNwaGVyZS5sb2NhbCIsInNjb3BlIjpbIlNERENfRkVERVJBVElPTl9XUklURSIsIkFWTl9XUklURSIsIlNERENfTUFOQUdFUl9SRUFEIiwiQ0VSVF9XUklURSIsIkNPTVBPU0FCSUxJVFlfV1JJVEUiLCJMSUNFTlNFX0tFWV9SRUFEIiwiQ09NUE9TQUJJTElUWV9SRUFEIiwiRURHRV9DTFVTVEVSX1dSSVRFIiwiVVNFUl9SRUFEIiwiQ1JFREVOVElBTF9XUklURSIsIkJBQ0tVUF9DT05GSUdfUkVBRCIsIkNMVVNURVJfV1JJVEUiLCJBVk5fUkVBRCIsIlZBU0FfUFJPVklERVJfUkVBRCIsIkRPTUFJTl9XUklURSIsIkNFSVBfUkVBRCIsIlNPU19XUklURSIsIlNERENfTUFOQUdFUl9XUklURSIsIk5UUF9XUklURSIsIkRFUE9UX0NPTkZJR19XUklURSIsIkRFUE9UX0NPTkZJR19SRUFEIiwiSE9TVF9XUklURSIsIkJBQ0tVUF9SRVNUT1JFX1JFQUQiLCJDRVJUX1JFQUQiLCJVU0VSX1dSSVRFIiwiVVBHUkFERV9SRUFEIiwiT1RIRVJfUkVBRCIsIlNPU19SRUFEIiwiU0VDVVJJVFlfQ09ORklHX1JFQUQiLCJDUkVERU5USUFMX1JFQUQiLCJIT1NUX1JFQUQiLCJDRUlQX1dSSVRFIiwiT1RIRVJfV1JJVEUiLCJMSUNFTlNFX0tFWV9XUklURSIsIkNBX1JFQUQiLCJORVRXT1JLX1BPT0xfV1JJVEUiLCJXQ1BfUkVBRCIsIkJBQ0tVUF9SRVNUT1JFX1dSSVRFIiwiTlRQX1JFQUQiLCJFREdFX0NMVVNURVJfUkVBRCIsIkJBQ0tVUF9DT05GSUdfV1JJVEUiLCJXQ1BfV1JJVEUiLCJTRVJWSUNFX0FDQ09VTlRfV1JJVEUiLCJORVRXT1JLX1BPT0xfUkVBRCIsIkNBX1dSSVRFIiwiQ0xVU1RFUl9SRUFEIiwiVkFTQV9QUk9WSURFUl9XUklURSIsIkROU19XUklURSIsIlZSU0xDTV9XUklURSIsIkROU19SRUFEIiwiU0VSVklDRV9BQ0NPVU5UX1JFQUQiLCJTRERDX0ZFREVSQVRJT05fUkVBRCIsIkRPTUFJTl9SRUFEIiwiVlJTTENNX1JFQUQiLCJVUEdSQURFX1dSSVRFIl0sInJvbGUiOlsiQURNSU4iXX0.K8zA-YhiLV32etkJgkakwyoGS30Vi-rRMgS2XfvuL2g"}
JAVA Code examples
Generate Access and Refresh Token
HttpPost post = new HttpPost("https://sddc-manager.vrack.vsphere.local/v1/tokens"); StringBuilder json = new StringBuilder(); /* Form the input data to be passed to the API */ json.append("{"); json.append("\"username\":\"[email protected]\","); json.append("\"password\":\"****\""); json.append("}"); post.setHeader("Content-Type", "application/json"); // send a JSON data post.setEntity(new StringEntity(json.toString())); try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(post)) { result = EntityUtils.toString(response.getEntity()); } JSONObject object = new JSONObject(result); /* Extract the access token from result of calling /v1/tokens */ String accessToken = object.get("accessToken").toString(); /* Extract the refresh token from result of calling /v1/tokens */ JSONObject refreshTokenObject = (JSONObject) object.get("refreshToken"); String refreshToken = refreshTokenObject.get("id").toString();
Code for calling a sample API with access token passed in HEADER
HttpGet request = new HttpGet("https://sddc-manager.vrack.vsphere.local/v1/users"); request.setHeader("Content-Type", "application/json"); /*Pass the accessToken as bearer token in the header */ request.setHeader("Authorization", "Bearer " + accessToken); try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(request)) { String result = EntityUtils.toString(response.getEntity()); System.out.println("OUTPUT of the API is " + result); }
Use a refresh token to generate new access token when the token is expired
HttpPatch httpPatch = new HttpPatch( "https://sddc-manager.vrack.vsphere.local/v1/tokens/access-token/refresh"); httpPatch.setEntity(new StringEntity(refreshToken)); httpPatch.setHeader("Content-Type", "application/json"); try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpPatch)) { result = EntityUtils.toString(response.getEntity()); /*If the generated token is enclosed with inverted commas remove that to avoid token mismatch error */ if (result.startsWith("\"") && result.endsWith("\"")) { result = result.substring(1, result.length() - 1); } } String newAccessToken = result;