How to secure web api with Identity Server 3 - asp.net-web-api

I'm building an MVC web app that uses the openID Connect hybrid flow to authenticate with Identity Server 3. The MVC web app contains jQuery scripts to get async JSON data from een ApiController. That ApiController is part of the same MVC web app.
I don't want that everyone is able to access the data from the API, so I want to secure the API as well. I added an [authorize] attribute to the ApiController. When requesting the API with a JQuery ajax request I get the following error message:
XMLHttpRequest cannot load
https://localhost:44371/identity/connect/authorize?....etc.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:13079' is therefore not allowed
access. The response had HTTP status code 405.
But, when I do a request to the API method directly in browser, I will be correct redirected to the Login page of Identity Server..
So, what's exactly the problem here? I read something about that requesting the /authorize endpoint is not allowed via 'back-channel', but I don't understand what's the difference between 'front-channel' and 'back-channel'. Is it possible that I mixed up the wrong OAuth flows? Is the Hybrid flow not the correct one maybe?
I also find out that the API is often a seperate app, but is it always neccessary / best-practice to build a seperate API app that for example requires a bearer token?
Please point me in the right direction about this.

The authorize method on your identity server does not allow ajax calls. Even specifying CORS headers is not going to help you in this particular case. Perhaps you could return a forbidden response instead of a redirect and manually redirect the client to the desired location via window.location

You need to allow your IdentityServer to be accessed from other domains, this is done by allowing "Cross Origin Resource Sharing" or CORS for short. In IdentityServer the simplest way to allow this is in your Client configuration for your Javascript Client, see this from the IdentityServer docs on CORS:
One approach to configuing CORS is to use the AllowedCorsOrigins collection on the client configuration. Simply add the origin of the client to the collection and the default configuration in IdentityServer will consult these values to allow cross-origin calls from the origins.
The error you're seeing is the browser telling you that when it asked IdentityServer if it allows requests from your Javscript client, it returned a response basically saying no, because the origin (http://localhost:13079) was not specified in the "Access-Control-Allow-Origin" response header. In fact that header wasn't in the response at all meaning CORS is not enabled.
If you follow the quickstart for adding a JavaScript client from the docs here all the necessary code is detailed there that you need for the Client config and to setup IdentityServer to allow CORS.

Related

How do API work with CORS policies to serve multiple apps

I am creating an API that would serve data to my frontend app. The API is on api.myapp.com and the app on www.myapp.com (same domain, just another subdomain). They communicate with AJAX requests and CORS is all set up, working fine.
But I have another app on another domain (www.myotherapp.com) which partialy uses the same data as myapp, so I was thinking of reusing the API so myotherapp could requests data from it too.
I think it is one use case of API, to be reusable, right?
But then, there is something that I may have missed, because as my API has CORS enabled with "Access-Control-Allow-Origin: www.myapp.com", it won't allow other apps to use its endpoints, right? Their AJAX requests would fail with CORS policies.
So how are public API built and configured? How should I set my API so it can serve several apps (ideally, only the ones I allow)?
Thanks for the explanations :)
There is an Origin header in the request and your API should check if this header is one of the allowed. If it is, then return it as an Access-Control-Allow-Origin header.
If the API is public, it can returns * as Access-Control-Allow-Origin header.

Jmeter - Getting 403 forbidden errors on custom api's while running a login script of sharepoint login

I'm getting 403 error on each custom rest api while executing the sharepoint login.
Could you please share with me a solution with an example?
This error comes
{"error":{"code":"-2147024891,
System.UnauthorizedAccessException","message":{"lang":"en-US","value":"Access
denied. You do not have permission to perform this action or access
this resource."}}}
Most probably you need to add proper authentication context to each API request and the most common way to protect the API from unauthorized usage is requirement to have valid Authorization header.
Inspect the outgoing requests to your custom API using your browser's developer tool and pay attention to the request headers in the "Network" tab, I believe you should see the aforementioned "Authorization" header or Cookie header or something like this.
In your JMeter script you can add custom headers to your requests using HTTP Header Manager
JMeter should handle Cookies automatically given you add HTTP Cookie Manager to your Test Plan.

No 'Access-Control-Allow-Origin' header is present on the requested resource does not apply to postman

I have implemented a restful service. I have tested it using an ajax request within the application and also with postman client and both worked. But when i try to send an ajax request from a different application i get the below error in browser console.
http://localhost:8080/AusIncomeCalculator/AUSTax/post. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8089' is therefore not allowed access.
I don't understand how the postman client get a successful response while the other applications cannot.
RESTful service is hosted in JBOSS-eap 7.0 with rest easy
What happen is for security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts.Postman is a REST Client that runs as an application inside the Chrome browser. It is specifically designed for testing rest APIs, and therefore it doesn't restrict cross origin resource request.

WAAD doesn't refresh access token from javascript

For applications that authenticate users with Windows Azure Active Directory(WAAD), unable to refresh token from javascript.
All the resources are protected by Authorize attribute makes calls to login.windows.net/{0} if token is expired. If the request is from page load it works as expected but if the request is from javascript ajax call it is unable make call to login.windows.net/{0}. It returns with status 302 and message
XMLHttpRequest cannot load https://login.windows.net/xxx.
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'xxx' is therefore not allowed access.
How to refresh the token from javascript calls?
It looks like you secured your web API with a method more suited for web UX.
Take a look at ADAL JS for a more reliable way of dealing with javascript driven apps: http://www.cloudidentity.com/blog/2014/10/28/adal-javascript-and-angularjs-deep-dive/
For an explanation of how token renewal works, see the video linked in that post
HTH
V.

AJAX calls to web service with HTTPS protocol

I plan to use https to build a website. After the user logs in, s/he is directed to a dashboard. The dashboard will be developed using javascript and html5. What are the thing I need to keep in mind when I make ajax calls using SOAP to a web service while using https?
The most important things:
always use the same domain name, otherwise browser will throw cross domain errors,
always use https protocol for every ajax request, so browser won't get same origin errors.
On the server side check for X-Requested-With: XMLHttpRequest HTTP header, to be sure that the request came as AJAX, not standalone GET/POST request. This is only difference.
With AJAX request browser will send the same cookies value as in the any other request, so you can surely check user session with it.

Resources