Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Integrate OpenID into MVC4 Web API

I am writing a Web API using MVC4 that should be consumed by multiple client types. I want to use the OpenID to authenticate.

I already have downloaded the DotNetOpenAuth NuGet package, but so far all of the examples are for a client app, rather than an API.

My problem is simple. I want to have clients send an authentication request to my API. The API authenticates with an OpenID provider. The API then sets whatever it needs to in order to use the [Authorize] tags throughout the web api calls.

I understand that in .NET applications, that the FormsAuthentication.SetCookie could be called, but is this also an easy-to-implement solution for other languages?

The question in a nutshell. How do I integrate OpenID into an MVC4 web api that allows for the use of the Authorize tag that can be called and consumed by multiple languages?

like image 535
Quickhorn Avatar asked Sep 03 '12 14:09

Quickhorn


People also ask

How do I connect to OpenID?

OpenID Connect (OIDC) is an identity layer built on top of the OAuth 2.0 framework. It allows third-party applications to verify the identity of the end-user and to obtain basic user profile information. OIDC uses JSON web tokens (JWTs), which you can obtain using flows conforming to the OAuth 2.0 specifications.

What's the difference between OpenID and OAuth in Web API?

OpenID vs. OAuth. Simply put, OpenID is used for authentication while OAuth is used for authorization. OpenID was created for federated authentication, meaning that it lets a third-party application authenticate users for you using accounts that you already have.

Is OpenID Connect OAuth?

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.


1 Answers

You may be confusing the roles of authentication and authorization. It sounds like your Web API needs both.

Let's start with authorization. Every API (that is, a web URL that is accessed by a client app other than a browser) either permits anonymous access or must be authorized (i.e. authorization). Authorization is OAuth's domain. OAuth (v2, presumably) describes how a client authorizes a call to your WebAPI.

Presumably as part of the authorization process, a user logs into your service. This step of logging in the user is authentication. And it is orthogonal to authorization. Whether you authenticate the user via OpenID, username/password, X.509 cert, etc., should be irrelevant to how your WebAPI calls are authorized. In other words, your WebAPI methods shouldn't care how the user authenticated (read: no OpenID ties whatever). What they'll have is an authorization filter applied to them that verifies the authorization on an incoming request and translates it to a few pieces of information including the username of the account that authorized the access, the level of access, the id of the authorized client, etc.

So a step at a time, the whole scenario might go something like this:

  1. A user operating a 3rd party client app (let's assume for simplicity that this client app is a 3rd party web application) wants to use functionality that requires the client access your WebAPI in the user's name.
  2. The client needs to obtain authorization for limited impersonation of the user as the client makes calls to your WebAPI. They start with an OAuth 2 redirect to the authorization endpoint at your service. If this is implemented using DotNetOpenAuth this could use the WebServerClient class.
  3. Your authorization endpoint fills the role of an OAuth 2 Authorization Server, and as such, uses DotNetOpenAuth's AuthorizationServer class. The first thing it does is check to see if there is an ASP.NET forms authentication cookie included in the request. This cookie is a natural indication as to whether the user has logged into your service on their browser already, and if so, who that user is. Checking for this cookie is a simple call to Controller.User. Note that your authorization endpoint is MVC rather than WebAPI because its response is to the browser/user, not the client app. Let's assume there is no such cookie and Controller.User is null (or User.Identity.IsAuthenticated is false). Refer to the OAuthAuthorizationServer sample for how to implement this endpoint.
  4. Your authorization endpoint responds with a redirect to the user login page, including a redirectUrl parameter in the query string that retains the full incoming OAuth 2 authorization request URL.
  5. Your user login page is an MVC endpoint that acts as an OpenID Relying Party. This endpoint uses DotNetOpenAuth's OpenIdRelyingParty class. Note that this endpoint knows nothing of OAuth 2 or authorization stuff. It merely authenticates the user. After authenticating the user, it redirects back to the URL in the redirectUrl argument. Refer to the OpenIdRelyingPartyMvc sample for how to do this.
  6. The authorization endpoint repeats its prior step, except this time there is a FormsAuthentication cookie so it proceeds to display a page to the user asking if they want to authorize the client to access the user's data. The user clicks yes. (beware: implement XSRF and clickjacking mitigations on this user authorization page).
  7. The authorization endpoint processes the user's affirmative response and calls AuthorizationServer to create the authorization record and return the response to the client. One of the results of this call is the formulation of a redirect response to the client that gives it an authorization code.
  8. The browser is now pulling at a URL of the client app that passes it the authorization code. The client then uses the WebServerClient class to exchange the authorization code for an access token (and usually a refresh token as well).
  9. The client app now makes calls to your WebAPI URLs directly, including the access token it obtained via OAuth 2 in the HTTP Authorization header.
  10. Your WebAPI fills the role of the OAuth2 Resource Server, and the authorize filter attribute you apply to your WebAPI methods to validate the incoming OAuth 2 access token uses the DotNetOpenAuth ResourceServer class to do its work. You can refer to the OAuthResourceServer sample, or even better, David Christiansen's WebAPI sample for how to do this.

That's the whole story. And yes, the client role is easy to write regardless of language or library that they happen to be using.

BTW, the DotNetOpenAuth samples I refer to are not distributed via NuGet. You get the samples from SourceForge.

like image 167
Andrew Arnott Avatar answered Nov 05 '22 20:11

Andrew Arnott