For this workflow, I am using the API Manager Reference VM 7.5.1
For the purpose of this workflow, here is what you need to know about the OAuth flow:
- Client app needs to request an token (access and refresh) from an OAuth server using the OAuth Client ID and Secret and user login credentials
- Then the client requests to the data APIs must pass the (access) token in the header of each requests
- Once the (access) token expires (401 error), use the refresh token to get a new access token
-
You should have a published Arrow Builder app and associated Swagger for virtualizing in the API GW
-
Instead of API Key auth on your virtualized API, use OAuth and accept defaults
-
Create a new client app and enable OAuth to get a Client ID and Secret
Client ID: 2dbf6d79-90f4-4c4d-8c16-60a1f0296daf Secret Key: c5230981-a818-4272-8232-ee500e5a5d45
The client app needs to get an access token (and refresh token) as follows:
-
Use the following user to make a POST to the OAuth server at :8089/api/oauth/token
username: regadmin password: changeme
-
and the following body parameters:
client_id client_secret grant_type username password
-
for example, via curl, using:
curl -X POST -H "Cache-Control: no-cache" -H "Postman-Token: 270e15b9-2549-ab49-f925-789bb3579e29" -H "Content-Type: application/x-www-form-urlencoded" -d 'client_id=2dbf6d79-90f4-4c4d-8c16-60a1f0296daf&client_secret=c5230981-a818-4272-8232-ee500e5a5d45&grant_type=password&username=regadmin&password=changeme' "https://10.156.68.169:8089/api/oauth/token"
-
Or using POSTMAN:
-
Sample response is shown below
{ "access_token": "rpn9dErdbNrX4MhMV38jBFiDVg2kgnJ3JtJbMuahh94rzTyZ5M4sqS", "token_type": "Bearer", "expires_in": 3599, "refresh_token": "Qm063yhdqN12qZDNfoda4Ua4YFFsM7imH3K73hmLSdziab", "scope": "resource.WRITE resource.READ" }
Now, the client can access the data API's by passing in the access token in a header:
Authorization: Bearer <access_token>
Here is a sample curl command:
curl -X GET -H "Authorization: Bearer rpn9dErdbNrX4MhMV38jBFiDVg2kgnJ3JtJbMuahh94rzTyZ5M4sqS" -H "Cache-Control: no-cache" -H "Postman-Token: 9bfce815-9566-2e1f-4987-6c95924c6fcc" "https://10.156.68.169:8065/api/account"
and in POSTMAN:
and the API response:
{
"success": true,
"request-id": "d77f7380-851d-4030-804d-14c078a95e03",
"key": "accounts",
"accounts": [
{
"id": "001i000000PscewAAB",
"Name": "GenePoint",
"Type": "Customer - Channel",
"Phone": "(650) 867-3450"
},
{
"id": "001i000000PscexAAB",
"Name": "United Oil & Gas, UK",
"Type": "Customer - Direct",
"Phone": "+44 191 4956203"
},
...
{
"id": "001i000000Pscf6AAB",
"Name": "United Oil & Gas Corp.",
"Type": "Customer - Direct",
"Phone": "(212) 842-5500"
}
]
}
POSTMAN provides a javascript XHR code snipet we can use as a starting point for our Titanium code to get a token.
Here is the Titanium code to request a token from the API GW OAuth server:
var access_token, refresh_token;
var data = "client_id=2dbf6d79-90f4-4c4d-8c16-60a1f0296daf&client_secret=c5230981-a818-4272-8232-ee500e5a5d45&grant_type=password&username=regadmin&password=changeme";
var xhr = Ti.Network.createHTTPClient({
onload: function onLoad() {
Ti.API.debug("Loaded: " + this.status + ": " + this.responseText);
var response = JSON.parse(this.responseText);
access_token = response.access_token;
// Ti.API.debug("access_token = "+response.access_token);
// Ti.API.debug("refresh_token = "+response.refresh_token);
refresh_token = response.refresh_token;
},
onerror: function onError() {
Ti.API.debug("Errored: " + this.status + ": " + this.responseText);
alert("Error reaching OAuth Token Server. Please try again later.");
}
});
xhr.open("POST","https://10.156.68.169:8089/api/oauth/token");
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
xhr.send(data);
Here is the Titanium code to call an API and pass the token in the header:
var xhr = Ti.Network.createHTTPClient({
onload: function onLoad() {
Ti.API.debug("Loaded: " + this.status + ": " + this.responseText);
var response = JSON.parse(this.responseText);
},
onerror: function onError() {
Ti.API.debug("Errored: " + this.status + ": " + this.responseText);
alert("Error reaching API Server. Please try again later.");
}
});
xhr.open("GET","https://10.156.68.169:8065/api/account");
xhr.setRequestHeader("Authorization", "Bearer "+access_token);
xhr.send();
Now you need to add the code to deal with expired tokens, etc...
At some point the access_token will expire and you will get a 401 reply. You can try the refresh_token against the same /api/oauth/token API and if the refresh_token was not also expired, you will get a new access_token AND refresh_token
For example, assume the tokens are retrieved via login as follows:
POST /api/oauth/token HTTP/1.1
Host: 192.168.1.65:8089
Cache-Control: no-cache
Postman-Token: e18029ba-ad95-9ac9-5759-fec86fb1bbc4
Content-Type: application/x-www-form-urlencoded
client_id=96528e9d-6cda-4c54-8a5c-32b12cc0c1c4&client_secret=f6e977b6-4fd9-4807-a26f-e18e08192485&grant_type=password&username=regadmin&password=changeme
With the following reply:
{
"access_token": "ezhy3ADmqTJZYRogM3naeP3Vj7RkcdrWRdi5waUW0FpXCpStIWEbUl",
"token_type": "Bearer",
"expires_in": 3599,
"refresh_token": "OaspjV9Ej6UbIXlc38Z6XSc4rUAlPH6iKlkneQdqhsyADD",
"scope": "resource.WRITE resource.READ"
}
To get a new access token make the following call:
POST /api/oauth/token HTTP/1.1
Host: 192.168.1.65:8089
Cache-Control: no-cache
Postman-Token: bf841851-58be-3d09-03e3-90f4f222a489
Content-Type: application/x-www-form-urlencoded
client_id=96528e9d-6cda-4c54-8a5c-32b12cc0c1c4&client_secret=f6e977b6-4fd9-4807-a26f-e18e08192485&grant_type=refresh_token&refresh_token=OaspjV9Ej6UbIXlc38Z6XSc4rUAlPH6iKlkneQdqhsyADD
With the following reply:
{
"access_token": "omo4g5icRQoL2K7VZBcLQjrZajl6ie5c9kMLewPs8IHQzi1q1rO500",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "6NRRaPz6UR8P9Fi32G2K9or684bbwsGzpWpw09bsRo7r3y",
"scope": "resource.WRITE resource.READ"
}
Refer to this blog post for a full, proper Alloy implementation of the mobile app to perform OAuth Authentication, including using the refresh token to retrieve new access tokens.