Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Authentication in ASP.NET Core for your Web API and Angular2

DZone's Guide to

Authentication in ASP.NET Core for your Web API and Angular2

Authentication in a single page application is a bit more special if you only know the traditional ASP.NET way. Token-based authentication is the best solution.

· Integration Zone
Free Resource

Learn how API management supports better integration in Achieving Enterprise Agility with Microservices and API Management, brought to you in partnership with 3scale

Authentication in a single page application is a bit more special if you only know the traditional ASP.NET way. To imagine that the app is a completely independent app like a mobile app helps. Token-based authentication is the best solution for this kind of apps. In this post, I'm going to try to describe a high-level overview and to show a simple solution.

Intro

As written in my last posts about Angular2 and ASP.NET Core, I reduced ASP.NET Core to just an HTTP Service, to provide JSON-based data to an Angular2 client. Some of my readers asked me about how the Authentication is done in that case. I don't use any server-generated log in page, registration page or something like this. So the ASP.NET Core part only provides the web API and the static files for the client application.

There are many ways to protect your application out there. The simplest one is using an Azure Active Directory. You could also setup a separate authentication server using IdentityServer4 to manage the users, roles and to provide a token based authentication.

And that's the key word: A Token Based Authentication is the solution for that case.

With the token bases authentication, the client (the web client, the mobile app, and so on) gets a string-based encrypted token after a successful log-in. The token also contains some user info and info about how long the token will be valid. This token needs to be stored on the client side and needs to be submitted to the server every time you request a resource. Usually, you use an HTTP header to submit that token. If the token is not longer valid you need to perform a new log-in.

In one of our smaller projects, didn't set-up a different authentication server and we didn't use Azure AD because we needed a fast and cheap solution. Cheap from the customers perspective.

The Angular2 Part

On the client side, we used angular2-jwt, which is an Angular2 module that handles authentication tokens. It checks the validity, reads meta information out of it and so on. It also provides a wrapper around the Angular2 HTTP service. With this wrapper, you are able to automatically pass that token via an HTTP header back to the server on every single request.

The workflow is like this.

  1. If the token is not valid or doesn't exist on the client, the user gets redirected to the log-in route.
  2. The user enters his credentials and presses the log-in button.
  3. The date gets posted to the server where a special middleware handles that request.
    1. The user gets authenticated on the server side.
    2. The token, including a validation date and some meta date, gets created.
    3. The token gets returned back to the client.
  4. The client stores the token in the local storage, cookie or whatever, to use it on every new request.

The angular2-jwt does the most magic on the client for us. We just need to use it to check the availability and the validity every time we want to do a request to the server or every time we change the view.

This is a small example about how the HTTP wrapper is used in Angular2:

import { AuthHttp, AuthConfig, AUTH_PROVIDERS } from 'angular2-jwt';

...

class App {

  thing: string;

  constructor(public authHttp: AuthHttp) {}

  getThing() {
    // this uses authHttp, instead of http
    this.authHttp.get('http://example.com/api/thing')
      .subscribe(
        data => this.thing = data,
        err => console.log(err),
        () => console.log('Request Complete')
      );
  }
}

The ASP.NET Part

On the server side, we also use a separate open source project called SimpleTokenProvider. This is really a pretty simple solution to authenticate the users, using his credentials and to create and provide the token. I would not recommend using this way in a huge and critical solution. In that case, you should choose the IdentiyServer or any other authentication like Azure AD to be more secure. The sources of that project need to be copied into your project and you possibly need to change some lines i.e., to authenticate the users against your database or whatever you use to store the user data. This project provides a middleware, which is listening on a defined path, like /api/tokenauth/. This URL is called with a POST request by the log-in view of the client application.

The authentication for the web API, is just using the token, sent with the current request. This is simply done with the built-in IdentiyMiddleware. That means, if ASP.NET MVC gets a request to a Controller or an Action with an AuthorizeAttribute, it checks the request for incoming Tokens. If the Token is valid, the user is authenticated. If the user is also in the right role, he gets authorized.

We put the users role information as additional claims into the Token, so this information can be extracted out of that token and can be used in the application.

To find the users and to identify the user, we use the given UserManager and SignInManager. These managers are bound to the IdentityDataContext. These classes are already available when you create a new project with Identity in Visual Studio.

This way we can authenticate a user on the server side:

public async Task<ClaimsIdentity> GetIdentity(string email, string password)
{
    var result = await _signInManager.PasswordSignInAsync(email, password, false, lockoutOnFailure: false);
    if (result.Succeeded)
    {
        var user = await _userManager.FindByEmailAsync(email);
        var claims = await _userManager.GetClaimsAsync(user);

        return new ClaimsIdentity(new GenericIdentity(email, "Token"), claims);
    }

    // Credentials are invalid, or account doesn't exist
    return null;
}

And these claims will be used to authenticate the Jwt-Token in the Token Authenticate middleware: 

var username = context.Request.Form["username"];
var password = context.Request.Form["password"];

var identity = await identityResolver.GetIdentity(username, password);
if (identity == null)
{
    context.Response.StatusCode = 400;
    await context.Response.WriteAsync("Unknown username or password.");
    return;
}

var now = DateTime.UtcNow;

// Specifically add the jti (nonce), iat (issued timestamp), and sub (subject/user) claims.
// You can add other claims here, if you want:
var claims = new[]
{
    new Claim(JwtRegisteredClaimNames.Sub, username),
    new Claim(JwtRegisteredClaimNames.Jti, await _options.NonceGenerator()),
    new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(now).ToString(), ClaimValueTypes.Integer64)
};

// Create the JWT and write it to a string
var jwt = new JwtSecurityToken(
    issuer: _options.Issuer,
    audience: _options.Audience,
    claims: claims,
    notBefore: now,
    expires: now.Add(_options.Expiration),
    signingCredentials: _options.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

var response = new
{
    access_token = encodedJwt,
    expires_in = (int)_options.Expiration.TotalSeconds,
    admin = identity.IsAdministrator(),
    fullname = identity.FullName(),
    username = identity.Name
};

// Serialize and return the response
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(response, _serializerSettings)

Conclusion

This is just a small overview. If you want to learn more and detailed information about how ASP.NET Identity works, you should definitely subscribe to the blogs of Dominick Baier and Brock Allen. Even the ASP.NET Docs are good resources to learn more about the ASP.NET Security.

Update: Just recently, Scott Brady wrote a blog post about getting Started with IdentityServer 4.

Unleash the power of your APIs with future-proof API management - Create your account and start your free trial today, brought to you in partnership with 3scale.

Topics:
authentication ,angular ,asp.net

Published at DZone with permission of Jurgen Gutsch. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}