The setup we have forbids a direct call to https://login.microsoftonline.com and hence I created a Proxy API in Azure APIM with a policy as follows:
Policy Type: Inbound
Get & set-variables from header (scope, client id, secret & grant type)
send-request to https://login.microsoftonline.com
set-method to POST
set-header Content-Type to x-www-form-urlencoded
set-body to return scope, client id, secret and grant type
get the response body
get the access token
set the token in a new body (liquid template)
set the body in return-response (convert body to string)
In APIM, I test this with all the required headers and I get an access token without any issues.
In Postman, I call my proxy API with all the required headers and I get an access token without any issues.
{
"status": "ok",
"token": "Bearer ASODIA@#$)(*ASDJASODNADSAOSDJ....PROPER TOKEN"
}
Now I do the same in my NodeJS code, call the same API with Headers (using Axios), I do get a proper response back BUT the Token returns empty!
{
"status": "ok",
"token": "Bearer "
}
Anybody has any idea on why this is happening and how I can solve this? If it was a CORS issue, I should have got an error instead of 200 OK and partial body! Or am I wrong in assuming that?
Thanks in advance...
SSG
router.get("/test", async (req, res) => {
let config = {
headers: {
client_id: process.env["BID"],
client_secret: process.env["BSEC"],
scope: process.env["BSCOPE"],
},
};
let data = {
"Content-Type": "application/json",
};
const apimUrl = "https://gateway-test.hapi.hmgroup.com/hapi-utils-auth/token";
axios
.get(apimUrl, data, config)
.then((response) => {
console.log(response.data);
res.send(response.data);
})
.catch((error) => {
console.log(error);
});
});
I have added the below given policy to the Echo API which gets created by default when we create an Azure APIM instance. I am able to fetch the Bearer token using this policy.
<policies>
<inbound>
<base />
<set-variable name="clientId" value="@(context.Request.Headers.GetValueOrDefault("client-id", ""))" />
<set-variable name="clientSecret" value="@(context.Request.Headers.GetValueOrDefault("client-secret", ""))" />
<set-variable name="grantType" value="@(context.Request.Headers.GetValueOrDefault("grant-type", ""))" />
<set-variable name="scope" value="@(context.Request.Headers.GetValueOrDefault("scope", ""))" />
<send-request mode="new" response-variable-name="tokenResponse" timeout="60" ignore-error="true">
<set-url>https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token</set-url>
<set-method>POST</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>@{
var body = $"client_id={Uri.EscapeDataString((string)context.Variables["clientId"])}&client_secret={Uri.EscapeDataString((string)context.Variables["clientSecret"])}&grant_type={Uri.EscapeDataString((string)context.Variables["grantType"])}&scope={Uri.EscapeDataString((string)context.Variables["scope"])}";
return body;
}</set-body>
</send-request>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<set-variable name="tokenResponseBody" value="@((String)((IResponse)context.Variables["tokenResponse"]).Body.As<string>(preserveContent: true))" />
<set-variable name="accessToken" value="@((string)JObject.Parse((string)context.Variables["tokenResponseBody"])["access_token"])" />
<return-response>
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>@{
var responseBody = new {
access_token = (string)context.Variables["accessToken"]
};
return JsonConvert.SerializeObject(responseBody);
}</set-body>
</return-response>
</outbound>
<on-error>
<base />
</on-error>
</policies>
I am able to get the bearer token as shown below-
Now I am trying to call the APIM Url in the NodeJS code to get the token.
app.js-
const express = require('express');
const testRouter = require('./sample.js');
const app = express();
const port = 3000;
app.use('/', testRouter);
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
sample.js-
const express = require('express');
const axios = require('axios');
const router = express.Router();
router.get("/test", async (req, res) => {
const headers = {
'client-id': '{client-id}',
'client-secret': '{client-secret}',
'scope': '{scope}',
'grant-type': 'client_credentials',
'ocp-apim-subscription-key': '{subscription-key}'
};
const apimUrl = "https://afreen-apimgmt.azure-api.net/echo/resource?param1=demo";
axios
.get(apimUrl, {
headers: headers,
})
.then((response) => {
console.log(response.data);
res.send(response.data);
})
.catch((error) => {
console.log(error);
res.status(500).send("Internal Server Error");
});
});
module.exports = router;
I am able to get the token successfully.
Follow my steps, you will get the response too.