Different Authentication Schemes for the Same ASP.NET Web API - authentication

The Situation
I have an upcoming project where the web pages will be making AJAX calls. External clients will also be provided a REST API. I will be implementing this project using ASP.NET MVC 4 with Web API.
I have seen various examples online where people use the [Authorize] attribute for security. I presume this is whenever Web API is called via AJAX on a web page.
I have also seen various examples where an API key was passed along with each request (via query string or header). I presume this is whenever Web API is called from an external system.
The Questions
Here are the questions that immediately come to mind:
Should I be creating a separate controller for internal and external clients?
or should I force the web pages to use the same external authentication model?
or is there a way that external clients can use the Authorize attribute?
or should I somehow support both forms or authentication at the same time?
A Side Note
A colleague pointed out that I might want to deploy the API to a totally different URL than where the web app is hosted. Along the same lines, he pointed out that the external API may need to be more coarse grain or evolve separately.
I don't want to reinvent the wheel, here. This makes me wonder whether I should be using Web API as an internal API for my AJAX calls in the first place or if I should stick to old-school MVC actions with [HttpPost] attributes.

[Authorize] attribute is not meant only for Ajax. When you apply the [Authorize] attribute to say an action method, what this does is it ensures the identity is authenticated before the action method runs,irrespective of the clients making the request and irrespective of the type of credentials submitted to your API. All it looks for is Thread.CurrentPrincipal. Here is the copy-paste of the code from the Authorize filter.
protected virtual bool IsAuthorized(HttpActionContext actionContext)
{
...
IPrincipal user = Thread.CurrentPrincipal;
if (user == null || !user.Identity.IsAuthenticated)
{
return false;
}
...
}
As you can see, all it does it gets the Thread.CurrentPrincipal and checks if the identity is authenticated. Of course, when you include the roles, there are additional checks.
So, what this means is that you will be able to use different means of authentication as long as Thread.CurrentPrincipal is set as a result of authentication. If you have two handlers (or HttpModules in case of web hosting) or authentication filters in case of Web API 2, you can establish the identity based on different factors. For example, you can have a BasicAuthnHandler and a ApiKeyHandler added to config.Handlers and hence run in the web API pipeline one after the other. What they can do is to look for the credentials and set Thread.CurrentPrincipal. If Authorize header comes in the basic scheme, BasicAuthnHandler will authenticate and set Thread.CurrentPrincipal and if the API key comes in, it does nothing and ApiKeyHandler sets Thread.CurrentPrincipal. Both handlers can create same type of prinicipal say GenericPrinicpal or even different one. It does not matter because all the principals must implement IPrincipal. So, by the time Authorize filter runs, Thread.CurrentPrincipal will be set and authorization will work regardless of how you authenticate. Note: If you web host, you will also need to set HttpContext.User as well, in addition to Thread.CurrentPrincipal.

Related

What is the recommended way to deal with large identity tokens with an MVC client?

I'm using IdentityServer4 for authentication, but one of the client apps is a simple MVC site with no API access. I initially set GetClaimsFromUserInfoEndpoint to true so that we could simply use the id token on requests. Everything works fine, but due to a large number of role claims associated with our users, the id token balloons, the auth cookie gets chunked, and we run into some issues with older browsers. So, I've set GetClaimsFromUserIndoEndpoint to false and looked for another way to get the claims we need on request.
I've written a custom owin middleware that queries the user info endpoint to add claims at the beginning of the request, with basic caching, but it seems quite a bit sloppier than it should. The MVC site is set to use hybrid mode, and on the beginning of the request hits the UserInfo endpoint with an access token, caches that info, and appends it to the ClaimsPrincipal.
This achieves my goals but seems like an abuse of access tokens, and I worry it may open us up to future problems since it requires access and refreshes token management.
Is there a better-recommended pattern for keeping id tokens slim, while hydrating them on request before authorization checks take place?
Thanks very much for any advice.

Look up the user with bearer token with Openiddict Core

I am currently using Openiddict, Identity and Entity Framework to manage my users and assign Bearer tokens to users to protect my API.
My infrastructure is currently using ASP.NET Core Web API in the back end and a separate React application in the front end. The React application makes HTTP calls to my API to retrieve it's data. There is no server side HTML rendering at all in the back end.
Everything works as I need it to for the most part. I can register users and retrieve tokens from the API. These tokens are included in my HTTP call in the Authorization header. My AuthorizationController uses this: https://github.com/openiddict/openiddict-samples/blob/dev/samples/PasswordFlow/AuthorizationServer/Controllers/AuthorizationController.cs with a few minor tweaks. My Startup.cs also uses almost exactly this https://github.com/openiddict/openiddict-samples/blob/dev/samples/PasswordFlow/AuthorizationServer/Startup.cs
In some instances, I need to make API calls to the endpoints that are specific to the user. For instance, if I need to know if a user has voted on a comment or not. Instead of passing along the users ID in a query string to get the user details, I would like to use the Bearer token I received that they use to make the API call for that endpoint. I am not sure how to do this though.
In some research I have done it looks like some samples use ASP.NET Core MVC as opposed to the API to retrieve the user with the User variable as seen here https://github.com/openiddict/openiddict-samples/blob/dev/samples/PasswordFlow/AuthorizationServer/Controllers/ResourceController.cs#L20-L31 however this seems not to apply to my infrastructure.
My question is how do I look up a user based on the Bearer token passed to the API to look up a users details from my database? I am assuming that all of the tokens passed out by the API are assigned to that specific user, right? If that's the case it should be easy to look them up based on the Bearer token.
The question is: How with Openiddict can you look up a user based on the token that was assigned to them for API calls? I need to get the user details before anything else can be done with the application first. Is there something baked internally or do I have to write my own support for this?
When you create an AuthenticationTicket in your authorization controller (which is later used by OpenIddict to generate an access token), you have to add a sub claim that corresponds to the subject/entity represented by the access token.
Assuming you use the user identifier as the sub claim, you can easily extract it from your API endpoints using User.FindFirst(OpenIdConnectConstants.Claims.Subject)?.Value and use it to make your DB lookup.

Get JSON Web Token payload data within controller action

I'm implementing JWT based authorization for my ASP.NET Web API application with Angular2 SPA. All is well and clear regarding authorization flow except for one detail. I am wondering how to get JWT payload information within the Web API controller action?
Looking through the web I can't find any solution that I would go for, for example, setting Thread.Principal or something like that.
What are the recommended ways to accomplish that?
The normal process to handle a JWT token as authentication in ASP.NET is:
Get the token from the request and ensure is valid.
Create a principal based on the information contained within the token and associate it with the request.
This implies that the payload information within the token is available through the request principal usually in the form of claims. For example, if your JWT contains information about the user roles it would get mapped to a role claim available in the principal.
You don't mention if you're using OWIN or not so I'll assume OWIN for the example, but it shouldn't really matter or be much different at the controller level.
Despite the fact you're concerned only with the data consumption part, if curious, you can read through this set of tutorials about ASP.NET Web API (OWIN) for a more in-depth look on the whole process:
Introduction
Authentication (HS256)
Authorization
The last one would be the one with most interest , you'll note the following code snippet on that one:
[HttpGet]
[Authorize]
[Route("claims")]
public object Claims()
{
var claimsIdentity = User.Identity as ClaimsIdentity;
return claimsIdentity.Claims.Select(c =>
new
{
Type = c.Type,
Value = c.Value
});
}
This relies on the User.Identity available within the controller to list all the claims of the currently authenticated identity. Unless you have an authentication pipeline configured rather different then what it's the norm, these claims are mapped from the JWT payload your API receives.

Azure Mobile App refreshing tokens on server

Here's the background:
Need to authenticate with google/facebook/msa
Need to add our own claims to MobileServiceAuthenticationToken for use on client
Want to have refresh token capabilities (I know FB doesn't have that)
I have this working by LoginAsync and getting a MobileServiceAuthenticationToken back. Then I call a custom auth controller which has an [Authorize] attribute on it.
The custom auth controller copies some claims from the principal then adds our claims to those and creates a new token which it returns to the client.
Using the LoginAsync for all of this keeps the tokens flowing for all calls and that's great.
So, the token expires and I call RefreshUserAsync on the client. At this point the MobileServiceAuthenticationToken with our custom claims is replaced by the default one from the MobileAppService without our claims. I expect that.
So now I have to call the custom auth controller again to get our claims added back to the identity token.
This works, but it feels clumsy. And it's two round trips.
What I'm looking for is to refresh the identity provider access token on the server side, and in the same method, update the identity token with our stuff.
I'm aware of the /.auth/refresh call from the client side as an alternative to RefreshUserAsync. Is there a similar call I can make from my controller in the backend without setting up the whole System.Net.Http.HttpClient thing?
For example: I use this.User.GetAppServiceIdentityAsync<GoogleCredentials>( this.Request ) in the backend to get identity provider information without making HTTP calls.
Something like that?
Thanks in advance.
Short version - no.
Longer version - you need to call the /.auth/refresh on the backend on behalf of the user, then add your claims. The /.auth endpoints are on a different service that your backend does not have access to except via Http.
The GetAppServiceIdentityAsync() method still does a HttpClient call, so you aren't saving yourself a round trip.

Are Tokens based on Cookies Restful?

I'm building some RESTful API for my project based on Play Framework 2.X.
My focus is on the authentication mechanism that I implemented.
Currently, I make use of SecureSocial.
The workflow is:
An anonymous user calls a secured API
Server grabs any cookie Id (kind of authentication token) and checks for matching in the Play 2 cache. (cache contains an association between cookie Id (randomly generated) and the user Id, accessible from database.
If any matched, user is authorized to process its expected service.
If none matched, user is redirected to a login page, and when filled with valid credentials (email/password), server stores its corresponding authentication data on Play 2 cache, and sends the newly created Cookie containing only a custom Id (authentication token) to user and of course, secured through SSL.
While the cookie/token doesn't expire, the user can call secured api (of course, if authorized)
The whole works great.
However, after some search, I came across this post, and ...I wonder if I'm in the right way.
Indeed, dealing with cookies ("sessions" in Play's term), would break the rule Restfulness.
Because an api really considered as stateless should be called with ALL the needed data at once (credentials/tokens etc..). The solution I implemented needs both calls: one to authenticate, the other to call the secured API.
I want to make things well, and I wonder some things:
What about the use of Api keys? Should I implement a solution using them instead of this SecureSocial workflow? Api Keys would be sent at EVERY API CALL, in order to keep restfulness.
I think about it since I want my APIs to be reached by some webapps, mobiles and other kind of clients. None of all are forced to manage cookies.
What about OAuth? Should I really need it? Would it replace totally the usage of simple api keys? Always with this objective of several clients, this known protocol would be a great way to manage authentication and authorization.
In one word, should I implement another mechanism in order to be Restful compliant?
this is quite an old Q, but still worth answering as it may interest others.
REST does mandate statelessness, but authorization is a common exception when implementing.
The solution you described requires a single authorization process, followed by numerous service calls based on authorized cookie. This is analog to api keys or OAuth. There's nothing wrong with cookies as long as the service isn't of high-security nature and that you expire then after a reasonable time.
Integrating OAuth into your service sounds a bit of an overkill and is recommended only if you expose the API to 3rd parties (outside your organization).