ASP.NET 5 contains a middleware for consuming tokens – but not anymore for producing them. I personally have never been a big fan of the Katana authorization server middleware (see my thoughts here) – and according to this, it seems that the ASP.NET teams sees IdentityServer as the replacement for it going forward.
So let’s have a look at the bits & pieces and how IdentityServer can help in implementing authentication for MVC web apps and APIs.
IdentityServer
IdentityServer is an extensible OAuth 2.0 authorization server and OpenID Connect provider framework. It is different from the old authorization server middleware as it operates on a higher level of abstraction. IdentityServer takes care of all the protocol and data management details while you only need to model your application architecture using clients, users and resources (see the big picture and terminology pages).
IdentityServer is currently available as OWIN middleware only (as opposed to native ASP.NET 5 middleware) – that means it can be used in Katana-based hosts and ASP.NET 5 hosts targeting the “full .NET framework” aka DNX451. It does currently not run on the Core CLR – but we are working on it.
You wire up IdentityServer in ASP.NET 5 using the typical application builder extension method pattern:
public void Configure(IApplicationBuilder app)
{
var idsrvOptions = new IdentityServerOptions
{
Factory = new IdentityServerServiceFactory()
.UseInMemoryUsers(Users.Get())
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get()),
};
app.UseIdentityServer(idsrvOptions);
}
For this sample we use in-memory data sources, but you can connect to any data source you like.
The Users class simply defines two test users (Alice and Bob of course) – I won’t bore you with the details. Scopes on the other hand define the resources in your application, e.g. identity resources like email addresses or roles, or resource scopes that represent your APIs:
public static IEnumerable<Scope> Get()
{
return new[]
{
// standard OpenID Connect scopes
StandardScopes.OpenId,
StandardScopes.ProfileAlwaysInclude,
StandardScopes.EmailAlwaysInclude,
// API – access token will
// contain roles of user
new Scope
{
Name = “api1″,
DisplayName = “API 1″,
Type = ScopeType.Resource,
Claims = new List<ScopeClaim>
{
new ScopeClaim(“role”)
}
}
};
}
Clients on the other hand represent the applications that will request authentication tokens (also called identity tokens) and access tokens.
public static List<Client> Get()
{
return new List<Client>
{
new Client
{
ClientName = “Test Client”,
ClientId = “test”,
ClientSecrets = new List<Secret>
{
new Secret(“secret”.Sha256())
},
// server to server communication
Flow = Flows.ClientCredentials,
// only allowed to access api1
AllowedScopes = new List<string>
{
“api1″
}
},
new Client
{
ClientName = “MVC6 Demo Client”,
ClientId = “mvc6″,
// human involved
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
“http://localhost:2221/”,
},
// access to identity data and api1
AllowedScopes = new List<string>
{
“openid”,
“email”,
“profile”,
“api1″
}
}
};
}
With these definitions in place we can now add an MVC application that uses IdentityServer for authentication, as well as an API that supports token-based access control.
MVC Web Application
ASP.NET 5 includes middleware for OpenID Connect authentication. With this middleware you can use any OpenID Connect compliant provider (see here) to outsource the authentication logic.
Simply add the cookie middleware (for local signin) and the OpenID Connect middleware pointing to our IdentityServer to the pipeline. You need to supply the base URL to IdentityServer (so the middleware can fetch the discovery document), the client ID, scopes, and redirect URI (compare to our client definition we did earlier). The following snippet requests the user’s ID, email and profile claims in addition to an access token that can be used for the “api1” resource.
app.UseCookieAuthentication(options =>
{
options.AuthenticationScheme = “Cookies”;
options.AutomaticAuthentication = true;
});
app.UseOpenIdConnectAuthentication(options =>
{
options.Authority = “https://localhost:44300″;
options.ClientId = “mvc6″;
options.ResponseType = “id_token token”;
options.Scope = “openid email profile api1″;
options.RedirectUri = “http://localhost:2221/”;
options.SignInScheme = “Cookies”;
options.AutomaticAuthentication = true;
}
MVC Web API
Building web APIs with MVC that are secured by IdentityServer is equally simple – the ASP.NET 5 OAuth 2.0 middleware supports JWTs out of the box and even understands discovery documents now.
app.UseOAuthBearerAuthentication(options =>
{
options.Authority = “https://localhost:44300″;
options.Audience = “https://localhost:44300/resources”;
options.AutomaticAuthentication = true;
});
Again Authority points to the base-address of IdentityServer so the middleware can download the metadata and learn about the signing keys.
Since the built-in middleware does not understand the concept of scopes, I had to fix that with this:
app.UseMiddleware<RequiredScopesMiddleware>(
new List<string> { “api1″ });
Expect this be improved in future versions.
API Client
Tokens can be also requested programmatically – e.g. for server-to-server communication scenarios. Our IdentityModel library has a TokenClient helper class which makes that very easy:
async Task<TokenResponse> GetTokenAsync()
{
var client = new TokenClient(
“https://localhost:44300/connect/token”,
“test”,
“secret”);
return await client.RequestClientCredentialsAsync(“api1″);
}
…and using the token:
var client = new HttpClient();
client.SetBearerToken(response.AccessToken);
var result = await client.GetAsync(“http://localhost:2025/claims”);
The full source code can be found here.
Summary
IdentityServer can be a replacement for the Katana authorization server middleware – but as I said it is a different mindset, since IdentityServer is not protocol oriented – but rather focusing on your application architecture. I should mention that there is actually a middleware for ASP.NET 5 that mimics the Katana approach – you can find it here.
In the end it is all about personal preference, and most importantly how comfortable you are with the low level details of the protocols.
There are actually much more samples on how to use IdentityServer in the samples repo. Give it a try.
Filed under: .NET Security, ASP.NET, IdentityServer, OAuth, OpenID Connect, OWIN, WebAPI Image may be NSFW.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
