In the age of the “personalized web experience”, authentication and user management is a given, and it’s easier than ever to tap into third-party authentication providers like Facebook, Twitter, and Google. And it’s not just the wild, wild web that needs it. Businesses need ways to secure their APIs and identify users logged into their applications.

OpenID Connect is a protocol for authenticating users, built with the latest in security technologies. It is a specification by the OpenID Foundation describing the best way for the authentication “handshake” to happen. It lays out what an Identity Provider needs to provide in order to be considered “OpenID Connect Certified” and that makes it easier than ever to consume authentication as a service.

Why Not Use The Built-In Authentication Providers?

The authentication providers built into ASP.NET Core are outstanding, but there are some shortcomings. First, OAuth is NOT an authentication protocol. I know what you’re thinking: “What?!!?” But it’s not. It is an Authorization Specification, which many modern authentication protocols are built on.

Second, while OAuth does a great job of providing the necessary information for consumers to make authorization decisions, it says nothing about how that information will be exchanged securely. This led to every authentication provider having their own way of exchanging the OAuth information, which has led to a few well-publicized hacks. OpenID Connect fixes these problems by providing an authentication protocol that describes exactly how the exchange of authorization information happens between a subscriber and their provider.

So let’s see how this works.

Nothing Up My Sleeve

We’ll be using Visual Studio Code and the command line (don’t look at me like that, I like coding on my Mac). First, get the dotnet command-line program and Yeoman, then we can get a basic application started by using the Yeoman generator from OmniSharp. After running the yo aspnet command, it asks a couple of questions about the app we want to create.

The most important is to choose: Web Application Basic (without Membership and Authorization). We’re going to do those ourselves.

It should take a few seconds, and you’ll have a simple ASP.NET Core app ready to go. Just follow the instructions that Yeoman displays at the end of the creation to get the app up and running.

Getting an Identity Provider

Now we need an Identity Provider. We’re going to use Google, so we need to set up a client on Google’s Developer Dashboard. Once you’re logged in to your account, select the drop-down at the top right where your account information is and choose “Create a project…” from the bottom of the list.

Choose a name for the project (it could be the same as your ASP.NET project), click the create button and Google should start creating the new project for you.

When the project is created, you should see a Library page. We’ll be using the Google+ API in the Social APIs group. At the very top, click the “ENABLE” link and when it’s done, you should see a box show up right below the button.

Click the button that says “Go To Credentials” to add credentials to your project. The Google+ API is already selected as the API we’ll be using, but we want to tell Google that we’ll be calling the API from a Web server (e.g. node.js, Tomcat) and that we’ll be accessing User data.

Once you’ve done that, click the “What credentials do I need?” button and it will take you to the screen to create an OAuth 2.0 Client ID. You can call it whatever you like (or just leave it as is). The important parts are the origin and redirect URLs. We’ll use the local URL where the sample app runs for the origin and the same local URL with a path of /signin-oidc for the redirect URI and then click the “Create client ID” button.

On the Consent Screen, the only thing we need to add is the Product name shown to users. You can name it whatever you like, even the same thing as your Project. When you click the continue button, you’ll see a Download credentials section. Copy the Client ID for use in our application, and then click the done button. You might think that’s it, but we need one more piece of information from the project. Click on the link for the OAuth 2.0 Client we just created and copy the client secret from that page.

Now we’re ready to set up the authentication in our application!

Getting Auth’d with OpenID Connect

When you open your application in Visual Studio Code, you’ll notice that there is a project.json file. We’ll need to make some quick changes to that to get some dependencies we’ll need to make this work. In the dependencies section of the project.json document add:

"Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0", "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0", 1 2 3 4 "Microsoft.AspNetCore.Authentication.JwtBearer" : "1.0.0" , "Microsoft.AspNetCore.Authentication.Cookies" : "1.0.0" , "Microsoft.AspNetCore.Authentication.OpenIdConnect" : "1.0.0" ,

This will allow us to use JSON Web Tokens for authorization information, get them from the OpenID Connect provider (Google in our case) and store them in cookies for session management. You’ll need to run a quick dotnet restore command but don’t worry, once you save the file, VS Code will give you a button to click so you don’t have to go back to the command line. Now we’ll enter the meat of the OpenID Connect authentication.

Open the Startup.cs file, and on the first line of the Configure method add:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 1 2 JwtSecurityTokenHandler . DefaultInboundClaimTypeMap . Clear ( ) ;

This will clear any previous claim type maps. Then, between the app.UseStaticFiles(); and app.UseMvc(…); add:

app.UseCookieAuthentication(new CookieAuthenticationOptions(){ AuthenticationScheme = "Cookies", AutomaticAuthenticate = true }); 1 2 3 4 5 app . UseCookieAuthentication ( new CookieAuthenticationOptions ( ) { AuthenticationScheme = "Cookies" , AutomaticAuthenticate = true } ) ;

This tells the application that we want to store our session tokens in cookies. Then, we need to add the authentication instructions.

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions(){ AuthenticationScheme = "oidc", SignInScheme = "Cookies", Authority = "https://accounts.google.com", ResponseType = "code id_token", ClientId = "{Replace with your Google Client ID}", ClientSecret = "{Replace with your Google Client Secret}", GetClaimsFromUserInfoEndpoint = true, SaveTokens = true }); 1 2 3 4 5 6 7 8 9 10 11 app . UseOpenIdConnectAuthentication ( new OpenIdConnectOptions ( ) { AuthenticationScheme = "oidc" , SignInScheme = "Cookies" , Authority = "https://accounts.google.com" , ResponseType = "code id_token" , ClientId = "{Replace with your Google Client ID}" , ClientSecret = "{Replace with your Google Client Secret}" , GetClaimsFromUserInfoEndpoint = true , SaveTokens = true } ) ;

This is the important part, so we’ll go through it line by line.

The AuthenticationScheme gives out scheme a name and will be used to build the default callback url (~/sign-in/oidc).

The SignInScheme is used to set the sign-in middleware.

The Authority identifies the authorization endpoint for our Identity Provider. It is discoverable as part of the OpenID specification, and is located at: https://accounts.google.com/.well-known/openid-configuration.

The ResponseType is also specified in that document under “response_types_supported”. This tells the application I am expecting a coded token back from the provider.

The ClientId , and ClientSecret are pretty self-explanatory. We got them from Google when we signed up.

The GetClaimsFromUserInfoEndpoint setting tells the provider that if we’re successful authenticating, go ahead and make a call to the userinfo_endpoint (specified in the configuration document at the same URL we got the authorization_endpoint and the response_types_supported from).

Finally, we tell the application to save the token once it comes back from the provider.

That’s all there is to it, but how do we know it’s working? We could hook up a login form but there is an easier way.

Checking Our Work

All we really need to do is add an [Authorize] attribute to a controller method. That will certainly show us that it is going to the login on the provider, but it won’t show us what the provider is sending back. Let’s create page that will show us that information so we can make sure we’re getting what we think we’re getting from the provider.

Add a “Secure” method to the HomeController.cs controller.

[Authorize] public async Task<IActionResult> Secure() { return View(); } 1 2 3 4 5 6 [ Authorize ] public async Task < IActionResult > Secure ( ) { return View ( ) ; }

Then create a view to return:

@{ ViewData["Title"] = "Security"; } <h2>Secure</h2> <dl> @foreach (var claim in User.Claims) { <dt>@claim.Type</dt> <dd>@claim.Value</dd> } </dl> 1 2 3 4 5 6 7 8 9 10 11 12 13 @ { ViewData [ "Title" ] = "Security" ; } < h2 > Secure < / h2 > < dl > @ foreach ( var claim in User . Claims ) { < dt > @ claim . Type < / dt > < dd > @ claim . Value < / dd > } < / dl >

This will just loop through the claims and output them.

When you view the page, you should now see a list of the claims on the secure page.

Congratulations, you just set up OpenID Connect for authentication in your ASP.NET Core app!

Learn More

Interested in learning more about user authentication and token management in ASP.NET Core? You’re in the right place! Check out these awesome resources:

If you have any questions, comments, or suggestions, feel free to reach out to me by email or via Twitter @leebrandt.