Securing our HTTP API endpoints are one of the biggest challenges we face when writing so-called modern applications. There are multiple concerns that we need to cover when security is the issue but for those modern applications, the concerns are much bigger because you are no more under your trusted subsystem in your organization domain. Dominick Baier, Mr. Identity, has covered this topic several times:
This is where the OAuth 2.0 enters. OAuth 2.0 is a specification and defines an authorization framework which enables you to give limited access to the third party applications on behalf of the resource owner through one of the defined flows. I’m not going to duplicate the RFC 6749 here but I will highlight the things that I have found vital for the last couple of months when I have been working on an OAuth 2.0 Server implementation in .NET Framework. So, this post is mostly a brain dump.
First of all, there are a few terms that you have to know before you dip your toes in the OAuth water:
- Resource server: The server that holds the resource.
- Resource owner: The user which owns the specific resources.
- Authorization server: A server that authenticates the resource owner and issues access tokens to the client.
- Client: The application that requests access on a resource on behalf of the resource owner.
There are more terms that you will see when you start reading the specification but the above list should be enough for this blog post. From this point on, I will go through a few bullet points which come in handy as a checklist when designing an OAuth 2.0 authorization server and an HTTP service backed by that authorization server.
Give Scope-based Permissions
The best thing that OAuth specifies is the distinction between the client and the application (resource server) and this gives you a chance to think about your structure again after you read the specification. The application is where you handle your business and expose the certain data. The data exposed here may be tied to a resource owner (for example, user’s hotel bookings) but it doesn’t have to be. That data can be something that your application deals with directly with the user context (for example, the list of hotels).
You should probably see where I’m going with this. Each of your exposed HTTP endpoints need different level of access grant, permission, whatever you want to call it. The OAuth 2.0 helps you handles this as well in a standard way: scopes. A scope defines a level of access that the client acquired. In each OAuth flow, the client specifies which scopes it needs to obtain. Assume that your application is handles data for a travel and tourism company (just like Expedia) and the scopes would be similar to below list:
- Reading user hotel reservations
- Changes to user hotel reservations
- Making hotel reservations on behalf of a user
This list can go on. Handling access to a resource based on scopes in your HTTP service layer gives you a natural way of dealing with the resources. Thinktecture.IdentityModel library has a nice little authorization attribute for your ASP.NET Web API applications: ScopeAuthorizeAttribute. This attribute allows you to protect the each HTTP service endpoint based on required scopes.
Every Endpoint Should Require Authentication
It is certainly a valid situation if you have some endpoints which don’t require resource owner context. For example, a client application may want to get a list of hotels in a region (going with my Expedia sample here again). In that case, resource owner permission is not necessary. So, those endpoints can be exposed publicly without needing any type of authentication and authorization? Absolutely not! In such an environment, don’t ever design your HTTP service in this way. I have found out that requiring an identity in each endpoint of your HTTP service is vital. For cases where you see that resource owner context is not necessary, the client application can obtain the access token through the Client Credentials Grant and hit your HTTP service endpoints with the access token obtained through the client credentials grant.
DO Validate the Redirect URI
This is a must! You should always validate the redirect_uri parameter and try to match it with the client’s pre-registered redirect URIs for Authorization Code Grant and Implicit Grant requests. Unless you do this, your authorization server will be very dangerous! Potentially, you could be ending up redirecting the access token to anywhere.
Only One Grant Type + Client Credentials Grant for a Client
Besides the client credentials grant, only allow one grant type for a client. When you think about it, you should see that a client only needs one type of grant. A server based client application (a web application, for instance) will need Authorization Code Grant. An iPhone application will need Implicit Grant. So, on the way to issuing an access token, validate the grant type as well.
- The OAuth 2.0 Authorization Framework (RFC 6749)
- The OAuth 2.0 Authorization Framework: Bearer Token Usage (RFC 6750)
- OAuth 2.0 Dynamic Client Registration Core Protocol (Draft v16)
- OAuth2 – The good, the bad and the ugly
- Securing a Web API with Windows Server 2012 R2 ADFS and Katana
- OWIN OAuth 2.0 Authorization Server
- DotNetDoodle.OAuthServer - An OWIN based OAuth Server Implementation (A playground implementation)
- Thinktecture.AuthorizationServer - An implementation of an OAuth2 authorization server
- Thinktecture.IdentityModel.Client - .NET OAuth Client
- Dissecting the Web API Individual Accounts Template–Part 1: Overview
- Dissecting the Web API Individual Accounts Template–Part 2: Local Accounts
- Dissecting the Web API Individual Accounts Template–Part 3: External Accounts
- Step-by-Step Guide for Setting Up A Windows Server 2012 Domain Controller
- Extending device support in Active Directory
- Developer Preview of OAuth Code Grant and AAL for Windows Store Apps