How to stop infinite api request at backend? - react-hooks

In my dashboard component I am fetching all orders of a user inside useEffect hook. useEffect hook has a dependency of user & orders state.
useEffect(() => {
let isMounted = true;
fetch(`http://localhost:5000/allorders?email=${user?.email}`, {
headers: {
authorization: `Bearer ${localStorage.getItem("accessToken")}`,
},
})
.then((res) => res.json())
.then((data) => {
if (isMounted) {
setOrders(data);
}
})
.catch((error) => console.log(error));
return () => {
isMounted = false;
};
}, [user?.email, orders]);
The problem is I am having infinite api request at /allOrders endpoint of my express server. How can I prevent frontend client from sending infinite request at my backend server?
GET /allorders?email=admin#admin.com 304 - - 59.084 ms
GET /allorders?email=admin#admin.com 304 - - 63.304 ms
GET /allorders?email=admin#admin.com 304 - - 58.676 ms
GET /allorders?email=admin#admin.com 304 - - 57.991 ms
GET /allorders?email=admin#admin.com 304 - - 57.935 ms
GET /allorders?email=admin#admin.com 304 - - 59.366 ms
GET /allorders?email=admin#admin.com 304 - - 61.231 ms
GET /allorders?email=admin#admin.com 304 - - 57.709 ms
GET /allorders?email=admin#admin.com 304 - - 59.637 ms
GET /allorders?email=admin#admin.com 304 - - 69.139 ms
GET /allorders?email=admin#admin.com 304 - - 58.118 ms
GET /allorders?email=admin#admin.com 304 - - 58.127 ms
GET /allorders?email=admin#admin.com 304 - - 61.101 ms
GET /allorders?email=admin#admin.com 304 - - 64.198 ms
I have tried to render the component using useMemo & React.memo(). As I don't have much knowledge of react hooks I encountered multiple error and eventually failed to stop infinite api request.

Related

Not able to consume WEB API hosted in same server

Below web API returns JSON for the given ID.
http://aws-av-devser/Assigning_ID/api/QidMasters/2
It's working as expected in postman.
but when I try to consume this web API in different projects on the same server. I am getting
404 Not found Error
Below is the code to consume the web API
var uri = "http://aws-av-devser/Assigning_ID/api/QidMasters/2";
var response = await httpClient.GetAsync(uri);
Error Message :
{
StatusCode: 404,
ReasonPhrase: 'Not Found',
Version: 1.1,
Content: System.Net.Http.HttpConnectionResponseContent,
Headers:
{
Server: Microsoft-HTTPAPI/2.0
Date: Fri, 17 Jun 2022 17:59:28 GMT
Connection: close
Content-Type: text/html; charset=us-ascii
Content-Length: 315
}
}
Please correct me if I am missing something

Flask-SocketIO: Cannot connect to a namespace

I have problems connecting to my server via Websockets while using Flask-SocketIO. Everything works if I don't specify a custom namespace, but if I want to connect to a namespace I cannot connect. What am I doing wrong?
I made a small scratch program, which shows my problem:
### removed to make the post less long, see below ###
I'm pretty sure I connect the client wrong. But I don't know how to do it right. I looked through the SocketIO Client documentation, but couldn't find help.
EDIT:
To make it clearer, here is an updated version with just one socket:
from flask import Flask
from flask_socketio import SocketIO
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on("connect", namespace="/test")
def handle_connect():
print("heureka!")
return True
#app.route('/')
def index():
return """
<!DOCTYPE HTML>
<html>
<head>
<title>Flask-SocketIO Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js" integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket1 = io("http://127.0.0.1:5000/test");
socket1.on("connect", function() {
console.log("yay!")
});
</script>
</head>
<body>
Testing
</body>
</html>
"""
socketio.run(app, debug=True, log_output=True, use_reloader=False)
I can see the requests the socket is sending in my terminal:
(6548) wsgi starting up on http://127.0.0.1:5000
(6548) accepted ('127.0.0.1', 59354)
127.0.0.1 - - [30/Dec/2020 19:15:58] "GET / HTTP/1.1" 200 691 0.000000
127.0.0.1 - - [30/Dec/2020 19:15:58] "GET /socket.io/?EIO=4&transport=polling&t=NQqtHrO HTTP/1.1" 200 371 0.000997
127.0.0.1 - - [30/Dec/2020 19:15:59] "GET /socket.io/?EIO=4&transport=polling&t=NQqtI28 HTTP/1.1" 200 371 0.000997
127.0.0.1 - - [30/Dec/2020 19:16:00] "GET /socket.io/?EIO=4&transport=polling&t=NQqtILH HTTP/1.1" 200 371 0.000000
127.0.0.1 - - [30/Dec/2020 19:16:03] "GET /socket.io/?EIO=4&transport=polling&t=NQqtJ0u HTTP/1.1" 200 371 0.000996
127.0.0.1 - - [30/Dec/2020 19:16:08] "GET /socket.io/?EIO=4&transport=polling&t=NQqtKFD HTTP/1.1" 200 371 0.001002
127.0.0.1 - - [30/Dec/2020 19:16:13] "GET /socket.io/?EIO=4&transport=polling&t=NQqtLTa HTTP/1.1" 200 371 0.001024
The path option that you are using is not to specify the namespace, it is used to indicate a custom Socket.IO endpoint. Normally you do not need to set the path.
The namespace is given in the connection URL:
var socket1 = io("/test");
Or if you prefer an absolute URL:
var socket1 = io("http://localhost:5000/test");

Axios requests using authentication token sometimes fail in Safari

I'm developing a react (16.9.0) single page app that uses axios (0.19.0). The axios requests use token authentication to access a server running django-rest-framework (3.6.4) and django-cors-headers (3.1.1). The authentication tokens are generated by django-rest-auth (0.9.5) during login.
The app works reliably in Chrome and Firefox. In Safari, some of requests fail due to 401 errors.
This requests succeeds in all three browsers:
INFO basehttp: "GET /apis/games/?slug=pop HTTP/1.1" 200 60932```
the code that generates it looks like:
axios
.get(`${simplUrl}/apis/games/?slug=${gameSlug}`, {
headers: { Authorization: simplToken },
})
.then(res => {
this.setState({
game: res.data[0],
});
...
This request failed with Safari:
INFO basehttp: "OPTIONS /apis/runs/43 HTTP/1.1" 200 0
INFO basehttp: "DELETE /apis/runs/43 HTTP/1.1" 301 0
INFO basehttp: "OPTIONS /apis/runs/43/ HTTP/1.1" 200 0
WARNING basehttp: "DELETE /apis/runs/43/ HTTP/1.1" 401 58
but succeeded with Chrome:
INFO basehttp: "OPTIONS /apis/runs/43 HTTP/1.1" 200 0
INFO basehttp: "DELETE /apis/runs/43 HTTP/1.1" 301 0
INFO basehttp: "OPTIONS /apis/runs/43/ HTTP/1.1" 200 0
INFO basehttp: "DELETE /apis/runs/43/ HTTP/1.1" 204 0
the code that generates it looks like:
const url = `${simplUrl}/apis/runs/${run.id}`;
// console.log('url:', url);
axios
.delete(url, {
headers: { Authorization: simplToken },
})
.then(res => {
// console.log(res);
afterDelete();
});
The Safari 401 response was:
"detail": "Authentication credentials were not provided."
This is the information Safari logged for the failed DELETE request:
The DRF apis views use are based on this mixing:
class CommonViewSet(viewsets.ModelViewSet):
authentication_classes = (TokenAuthentication, BasicAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,)
For local development, the DRF server's CORS settings are:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
I don't understand why some requests fail in Safari while others do not. Mostly, I want to insure all requests work in all three browsers.
The solution was to add a trailing slash to urls referencing a single object. The DRF Router docs indicate the correct pattern is:
URL pattern: ^users/{pk}/$ Name: 'user-detail'
Whether it's a bug or a feature that Safari doesn't include the authentication token in redirected requests resulting a 401 error, I'll leave to the reader.
Did you see this ?,I'm not really sure but this discussion may help.
Also, as the error is related to token, try to verify that its sent or added to the request correctly or if it has a type like bearer or somthing.
Also try to log the incoming request headers and its body, so you can make sure that nothing is missing or corrupted.
As this issue happen with DELETE, try to comapre all requests to each other to find out what is missing.

How do I solve getting 401 Unauthorized in response to attempting to obtain a token?

I've got an Identity Server (using IdentityServer4), a Web API that uses the Identity Server for authorization, and a Xamarin application that is using the Identity Server to log-in and authenticate the API.
When I run all three parts locally from Visual Studio I'm able to login using the Xamarin app, obtain a token, and use that token to make API calls. However, when I publish the Identity Server to a web server (on the same network), it fails at the point that it tries to get the token. So, it shows the login page, appears to accept the login, but the POST to get the token fails with the 401 Unauthorised error in the response.
I've also configured the Identity Server to allow Swagger to connect for testing the API, and that does allow me to sign in (using Implicit) using the Identity Server installed on a Web Server.
This is the method that does the POST in the Xamarin app (mostly copied from the eShopOnContainers example):
public async Task<TResult> PostAsync<TResult>(string uri, string data, string clientId, string clientSecret)
{
HttpClient httpClient = CreateHttpClient(string.Empty);
if (!string.IsNullOrWhiteSpace(clientId) && !string.IsNullOrWhiteSpace(clientSecret))
{
AddBasicAuthenticationHeader(httpClient, clientId, clientSecret);
}
var content = new StringContent(data);
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
HttpResponseMessage response = await httpClient.PostAsync(uri, content);
await HandleResponse(response);
string serialized = await response.Content.ReadAsStringAsync();
TResult result = await Task.Run(() =>
JsonConvert.DeserializeObject<TResult>(serialized, _serializerSettings));
return result;
}
Here's the calling method for getting the token:
public async Task<UserToken> GetTokenAsync(string code)
{
string data = string.Format("grant_type=authorization_code&code={0}&redirect_uri={1}&code_verifier={2}",
code, WebUtility.UrlEncode(Settings.Service.IdentityCallback), _codeVerifier);
var token = await _requestProvider.PostAsync<UserToken>(
Settings.Service.IdentityTokenEndpoint, data, Settings.Service.IdentityClientId, Settings.Service.IdentityClientSecret);
return token;
}
The uri is "http://myserver:5002/connect/token" and headers are:
Accept: "application/json"
Authorization: "Basic SW5zdGVtLkFDSVMuTW9iaWxlOnNlY3JldA=="
ContentType: "application/x-www-form-urlencoded"
The log on the web server gives me this:
info: IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator[0]
Showing login: User is not authenticated
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 3.4723ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3D0dc5d79410db46739c798ce004ac89b8%26code_challenge%3DAuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c%26code_challenge_method%3DS256%26state%3D031db7b77c7249aebb6f7ae205dac016
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Login", controller = "Account"}. Executing action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) with arguments (/connect/authorize/callback?client_id=Company.App.Mobile&client_secret=secret&response_type=code%20id_token&scope=openid%20profile%20app_api%20offline_access&redirect_uri=http%3A%2F%2Fmyserver%3A5002%2FAccount%2FRedirect&nonce=0dc5d79410db46739c798ce004ac89b8&code_challenge=AuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c&code_challenge_method=S256&state=031db7b77c7249aebb6f7ae205dac016) - Validation state: Valid
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer), returned result Microsoft.AspNetCore.Mvc.ViewResult in 0.3611ms.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1]
Executing ViewResult, running view Login.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4]
Executed ViewResult - view Login executed in 1.7974ms.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) in 2.4715ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 3.1044ms 200 text/html; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/css/site.css
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /css/site.css was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.6236ms 304 text/css
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/lib/bootstrap/js/bootstrap.js
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /lib/bootstrap/js/bootstrap.js was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.3461ms 304 application/javascript
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/lib/jquery/jquery.js
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /lib/jquery/jquery.js was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.2798ms 304 application/javascript
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/icon.png
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /icon.png was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.2655ms 304 image/png
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/lib/bootstrap/css/bootstrap.css
info: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[6]
The file /lib/bootstrap/css/bootstrap.css was not modified
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.26ms 304 text/css
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 POST http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3D0dc5d79410db46739c798ce004ac89b8%26code_challenge%3DAuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c%26code_challenge_method%3DS256%26state%3D031db7b77c7249aebb6f7ae205dac016 application/x-www-form-urlencoded 712
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "Login", controller = "Account"}. Executing action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) with arguments (IdentityServer4.Quickstart.UI.LoginInputModel, login) - Validation state: Valid
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
AuthenticationScheme: idsrv signed in.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action method IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer), returned result Microsoft.AspNetCore.Mvc.ViewResult in 1.0902ms.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1]
Executing ViewResult, running view Redirect.
info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4]
Executed ViewResult - view Redirect executed in 10.0474ms.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action IdentityServer4.Quickstart.UI.AccountController.Login (Company.IdentityServer) in 12.3805ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 13.1928ms 302 text/html; charset=utf-8
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/connect/authorize/callback?client_id=Company.App.Mobile&client_secret=secret&response_type=code%20id_token&scope=openid%20profile%20app_api%20offline_access&redirect_uri=http%3A%2F%2Fmyserver%3A5002%2FAccount%2FRedirect&nonce=0dc5d79410db46739c798ce004ac89b8&code_challenge=AuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c&code_challenge_method=S256&state=031db7b77c7249aebb6f7ae205dac016
info: IdentityServer4.Hosting.IdentityServerMiddleware[0]
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint for /connect/authorize/callback
info: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint[0]
ValidatedAuthorizeRequest
{
"ClientId": "Company.App.Mobile",
"ClientName": "App Mobile",
"RedirectUri": "http://myserver:5002/Account/Redirect",
"AllowedRedirectUris": [
"http://myserver:5002/Account/Redirect"
],
"SubjectId": "eb194e4a-a2f7-482c-8c43-204567ebd591",
"ResponseType": "code id_token",
"ResponseMode": "fragment",
"GrantType": "hybrid",
"RequestedScopes": "openid profile app_api offline_access",
"State": "031db7b77c7249aebb6f7ae205dac016",
"Nonce": "0dc5d79410db46739c798ce004ac89b8",
"SessionId": "0ed1a950919c3b368e1249ec74e35f2c",
"Raw": {
"client_id": "Company.App.Mobile",
"client_secret": "secret",
"response_type": "code id_token",
"scope": "openid profile app_api offline_access",
"redirect_uri": "http://myserver:5002/Account/Redirect",
"nonce": "0dc5d79410db46739c798ce004ac89b8",
"code_challenge": "AuKmnO1hMcoEK3VeVNiVDka2U5F23HBnR0_MtxeWA3c",
"code_challenge_method": "S256",
"state": "031db7b77c7249aebb6f7ae205dac016"
}
}
info: IdentityServer4.Endpoints.AuthorizeCallbackEndpoint[0]
Authorize endpoint response
{
"SubjectId": "eb194e4a-a2f7-482c-8c43-204567ebd591",
"ClientId": "Company.App.Mobile",
"RedirectUri": "http://myserver:5002/Account/Redirect",
"State": "031db7b77c7249aebb6f7ae205dac016",
"Scope": "openid profile app_api offline_access"
}
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
AuthenticationScheme: idsrv signed in.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 40.3114ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET http://myserver:5002/Account/Redirect
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.9519ms 404
The address "http://myserver:5002/Account/Redirect" doesn't actually exist because the client is a Xamarin app, so I don't think the 404 at the end is an issue. There doesn't seem to be anything in the log for the call to obtain the token.
Here's the Client config for the Identity Server:
new Client
{
ClientName = "ACIS Mobile",
ClientId = "Instem.ACIS.Mobile",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = {$"{identityUri}/Account/Redirect"},
RequireConsent = false,
RequirePkce = true,
PostLogoutRedirectUris = {$"{identityUri}/Account/Redirecting"},
AllowedCorsOrigins = { "http://xamarinapp" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.OfflineAccess,
"acis_api"
},
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true
},
new Client
{
ClientName = "Swagger UI",
ClientId="swaggerui",
AllowedGrantTypes=GrantTypes.Implicit,
AllowAccessTokensViaBrowser=true,
RedirectUris = { $"{webApiUri}/oauth2-redirect.html" },
PostLogoutRedirectUris={ $"{webApiUri}/" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"acis_api"
}
}
The Identity server startup configuration is pretty simple:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddIdentityServer()
.AddInMemoryClients(Config.GetClients(Configuration))
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddTestUsers(Config.GetUsers())
//.AddDeveloperSigningCredential();
.AddSigningCredential("some certificate thumbprint", System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, NameType.Thumbprint);
services.AddAuthentication()
.AddMicrosoftAccount(options =>
{
options.ClientId = "someclientid";
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientSecret = "somesecret";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseIdentityServer();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
In IIS I've configured it to allow Anonymous and Basic authentication.
This is pretty much all new to me and I was making progress until this point, but I can't see any reason why it's giving me the 401 Unauthorized error, and I can't even see anything in any logs to give me anything to go on.
Edit:
I found a log file with more information:
2019-01-08 12:08:51 172.26.2.174 POST /Account/Login ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 5002 - 172.16.190.147 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+WebView/3.0)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/64.0.3282.140+Safari/537.36+Edge/17.17134 http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 302 0 0 156
2019-01-08 12:09:49 172.26.2.174 GET /connect/authorize/callback client_id=Company.App.Mobile&client_secret=secret&response_type=code%20id_token&scope=openid%20profile%20app_api%20offline_access&redirect_uri=http%3A%2F%2Fmyserver%3A5002%2FAccount%2FRedirect&nonce=dc06cb800d6f4f729df03a986ff2f165&code_challenge=N343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo&code_challenge_method=S256&state=86f26cf6a5184d9a8263aac954711819 5002 - 172.16.190.147 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+WebView/3.0)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/64.0.3282.140+Safari/537.36+Edge/17.17134 http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 302 0 0 593
2019-01-08 12:10:33 172.26.2.174 POST /connect/token - 5002 Company.App.Mobile 172.16.190.147 - - 401 1 1326 50
2019-01-08 12:10:33 172.26.2.174 GET /Account/Redirect - 5002 - 172.16.190.147 Mozilla/5.0+(Windows+NT+10.0;+WOW64;+WebView/3.0)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/64.0.3282.140+Safari/537.36+Edge/17.17134 http://myserver:5002/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3DCompany.App.Mobile%26client_secret%3Dsecret%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520app_api%2520offline_access%26redirect_uri%3Dhttp%253A%252F%252Fmyserver%253A5002%252FAccount%252FRedirect%26nonce%3Ddc06cb800d6f4f729df03a986ff2f165%26code_challenge%3DN343zy63pcw_E75ET0HZQWGU_5ALC6H6sXt836z6mzo%26code_challenge_method%3DS256%26state%3D86f26cf6a5184d9a8263aac954711819 404 0 0 15
It's the connect/token line that has the 401 error.
I had Basic Authentication enabled in IIS for the Identity Server. Once I turned that off, it works fine.

CORS issues with Serverless Lambda and API Gateway

Solved
The below issue was simply caused by the body property of the response object constructed in my Lambda. I was forgetting to stringify the data, returning body: data instead of body: JSON.stringify(data). This problem with the response appeared to trigger an error with API Gateway which caused the request failures with some rather confusing error messages.
Problem
I'm working on a ecommerce site using React, Serverless and the Stripe API. My front-end React app is making a GET request using Axios to my Lambda function which has been exposed via API Gateway. The Lambda function in turn queries the Stripe API and returns the Stripe response data to my React app. However, I am experiencing CORS issues as my React app tries to call the Lambda, it receives the following error:
Failed to load: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 502.
Querying the Lambda endpoint in Insomnia returns a 502 response with { "message": "internal server error" }. But executing the serverless invoke command from the Lambda function from the terminal successfully returns the Stripe data.
I am enabling cors for the function in my serverless.yml file and including 'Access-Control-Allow-Origin': '*' in my Lambda code response as advised in this Serverless blog post, I have also attempted adding a various combinations of the following headers to my Lambda response and my Axios request based on suggestions found on this issue on Axios and this issue on Serverless. I've deleted and redeployed the service multiple times and
Lambda response headers
headers: {
'Access-Control-Expose-Headers': 'Access-Control-Allow-Origin',
'Access-Control-Allow-Credentials': true,
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
React/Axios config
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
crossDomain: true
}
Currently my code is as follows:
React app
import Axios from 'axios';
import { GET_PRODUCTS_URL } from '../config';
export default () => {
return Axios
.get(GET_PRODUCT_URL, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
crossDomain: true
})
.then(({ data }) => data)
.catch(console.log);
}
Lambda
import Stripe from 'stripe';
const apiKey = process.env.STRIPE_SECRET_KEY;
const stripe = Stripe(apiKey);
module.exports.handler = (event, context, callback) => {
return stripe.products
.list()
.then(({ data }) => {
const response = {
statusCode: 200,
headers: {
'Access-Control-Expose-Headers': 'Access-Control-Allow-Origin',
'Access-Control-Allow-Credentials': true,
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: data,
};
callback(null, response);
})
.catch(console.log);
}
Serverless.yml
service: srd
provider:
name: aws
runtime: nodejs6.10
stage: ${opt:stage, self:custom.defaultStage}
region: eu-west-1
memorySize: 256
timeout: 6
versionFunctions: true
plugins:
- serverless-plugin-optimize
- serverless-plugin-scripts
package:
individually: true
functions:
get-products:
handler: lambda/get-products.handler
name: srd-get-products-${self:provider.stage}
description: 'get srd products from stripe'
environment:
STRIPE_PUBLISHABLE_KEY: ${self:custom.stripe_publishable_key.${self:provider.stage}}
STRIPE_SECRET_KEY: ${self:custom.stripe_secret_key.${self:provider.stage}}
events:
- http:
path: products
method: get
cors: true
custom:
defaultStage: dev
stripe_publishable_key:
dev: ${file(env.yml):STRIPE_DEV_PUBLISHABLE_KEY}
live: ${file(env.yml):STRIPE_LIVE_PUBLISHABLE_KEY}
stripe_secret_key:
dev: ${file(env.yml):STRIPE_DEV_SECRET_KEY}
live: ${file(env.yml):STRIPE_LIVE_SECRET_KEY}
I've been at this for hours, any insights much appreciated.
Edit/Additional
Making an options request from the CLI returns the following:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
Date: Mon, 19 Mar 2018 06:52:12 GMT
x-amzn-RequestId: 0d10c9d1-2b42-11e8-b270-a723e367048e
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent
Access-Control-Allow-Methods: OPTIONS,GET
Access-Control-Allow-Credentials: false
X-Cache: Miss from cloudfront
Via: 1.1 e40b14deb4a844594f746b751f632677.cloudfront.net (CloudFront)
X-Amz-Cf-Id: eMvu3Ke7m7GNFCFgIOGVJmoObFwYMeEt4o8AByoipfMn1nXIi9Vo0g==
The HTTP response code in the CORS error message says 502. This means the server you are requesting is unavailable.
In an event of a 502, the browser cannot make successful OPTIONS requests, so even if your CORS setup in the server is correct, you will still get a CORS error since it was not resolved properly.
Look at your server and make sure it is running as it should. Once the 502 error is fixed, try again and you should be good to go. Try making a manual OPTIONS request, similar to that of what the browser would make, and see if you get the same error.

Resources