I have a set of API calls that go through Azure APIM to reach our backend. All but one of the calls function as they should, given that the subscription key is included. However the function below, despite having the subscription key assigned in the header section, always results in a 401: access denied, missing subscription key
. To keep the post neat, I will exclude the extra types because they will quickly clutter the post, and I don't believe they are the cause.
export const webApiConfig: WebApiConfig = {
endpointUrl: process.env.REACT_APP_WEBAPI_ENDPOINT as string,
subscriptionKey: process.env.REACT_APP_WEBAPI_GATEWAY_SUBSCRIPTION_KEY as string,
};
export const trainProjectAsync = async (projectName: string): Promise<NluTrainingState> => {
try {
// Build the request url and config
const url: string = `${webApiConfig.endpointUrl}/Nlu/${projectName}/Train`;
const token = await getToken();
const requestConfig: AxiosRequestConfig = {
headers: {
Authorization: token,
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": webApiConfig.subscriptionKey,
},
signal: new AbortController().signal,
};
// Perform the POST request
const response = await axios.post<NluTrainingState>(url, requestConfig);
return response.data satisfies NluTrainingState;
} catch (error) {
// check whether the error is an axios error or a stock error.
if (axios.isAxiosError(error)) {
throw new Error(`API call axios malfunction code: ${error.code} ${JSON.stringify(error.response)}`);
} else {
throw new Error(`API call stock malfunction, reason: ${error}`);
}
}
};
This is the function that it's supposed to hit via the APIM (and testing it via postman or in swagger shows that this function works as it should). But when the API is locally hosted without API Gateway inbetween, the frontend API call will result in a 401
result as well.
[Authorize]
[HttpPost("{projectName}/Train")]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<NluTrainingStateDto>> TrainAsync(string projectName)
{
try
{
// Launch a training job.
NluTrainingStateDto result = await _nluService.TrainAsync(projectName);
// Return the correct status based on whether the request was a success.
if (result != null)
{
return Ok(result);
}
else
{
return NotFound();
}
}
catch (ServiceAccessException serviceEx)
{
// TODO: add logging
IError error = _errorFactory.CreateError(ErrorCode.ControllerNotServiced, _exceptionResourceManager.GetString("ConnectionNotServicedExc")!);
ControllerNotServicedException _controllerEx = new(error, serviceEx);
return StatusCode((int)HttpStatusCode.InternalServerError, $"Internal Server Error: {_controllerEx.Message}");
}
}
I've tried to make the request with four different methods, POST
, PATCH
, PUT
and GET
. All of them fail except for GET
, but I believe it breaks convention to use GET
for this request and am saving this as a last resort. I should note that this particular function used to work as a POST
request before
EDIT: The APIM is created via OpenAPI specification through swagger url.
This may come across as a bit odd, as this solution has failed me before.
I had the same problem today because I forgot to add a body to the post request. This time it was resolved by simply changing axios.post(url, config)
to axios.post(url, {}, config)
.
I am also aware that my OPs may sometimes be missing key information, that I thought was unimportant. I will try to improve on that.