static void

OAuth 2

OAuth 2 is supported using Owin middleware, so you have to use Owin.

Roles

In WS-Federation terms, Authorization server is an STS/Identity Provider (IdentityServer v3 and ADFS v4 support both OAuth2 and Ws-fed). The Relying Party/Service Provider role is split into two: client (uses data) and resource server (provides data).

Tokens

Access tokens are like cookies in traditional forms authentication:

You should normally request scopes when explicitly needed, not all in advance. The authorization API should include a "include_granted_scopes=true" to roll up previously granted scopes.

Flows

Google's OAuth documentation

The most common interactions are implicit/ token (javascript in the browser) and code (server page gets code and does a server-to-server post for the token). The latter never exposes the token, so it's more secure.

Generally you have to register the client with the auth server (so it knows where to redirect, or at least validate your redirect_uri).

Implicit Flow (Browsers/Apps)

Authorization Code Flow (Server-side)

Password (Secure servers only)

Client Credential (application-level access)

OpenID Connect

OpenID Connect is an authentication protocol built on top of OAuth2. OpenID identity providers (IdP) include 3rd parties like Google and Microsoft, plus your own with IdentityServer or ADFS 4.

In Startup do the following:

//always do cookie middleware first
 app.UseCookieAuthentication(new CookieAuthenticationOptions
 {
     AuthenticationType = "Cookies",
 });

 app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
 {
     Authority = "https://localhost:44324/core"//IdP Url,
     ClientId = "tst-infrabel.be"//OpenID server must have this client
     Scope = "openid profile roles"//what roles I want (default is openid)

     RedirectUri = "https://localhost:44348/"//start page for this application
     ResponseType = "code id_token token",

     SignInAsAuthenticationType = "Cookies",
     Notifications = new OpenIdConnectAuthenticationNotifications
     {
         AuthenticationFailed = context =>
                                {
                                    //logging errors
                                    Console.WriteLine(context.Exception);
                                    return Task.FromResult(0);
                                },
         //claims transformation
         SecurityTokenValidated = notification =>
         {
             var id = notification.AuthenticationTicket.Identity;

             // create new identity and set name and role claim type
             var nid = new ClaimsIdentity(id.AuthenticationType);
             //copy the claims in
             nid.AddClaim(id.FindFirst(ClaimTypes.Name));
             nid.AddClaims(id.FindAll(ClaimTypes.Role));
             // add new claim
             nid.AddClaim(new Claim("LogonTime"DateTime.UtcNow.ToString("u")));

             notification.AuthenticationTicket =
                 new AuthenticationTicket(nid, notification.AuthenticationTicket.Properties);

             return Task.FromResult(0);
         }
     }
 });

The client must use SSL. If you don't (e.g. local development), the client will enter an infinite redirect loop back to the IdP (you can also have this if the client URL doesn't end in "/").
In app.UseCookieAuthentication(new CookieAuthenticationOptions add:
CookieSecure = CookieSecureOption.Never
Obviously don't leave this is production- use the [RequireHttps] attribute.

SignOut

Use Request.GetOwinContext().Authentication.SignOut();

Client

A simple console client

static void Main(string[] args)
{
    var token = GetToken().Result;
    Console.WriteLine(token);
 
    var data = CallService(token).Result;
    Console.WriteLine(data);
}
 
private async static Task<string> GetToken()
{
    using (var client = new HttpClient())
    {
        var post =
            new Dictionary<string, string>
            {
                {"grant_type", "password"},
                {"username", "alice"},
                {"password", "secret"},
                //client
                {"client_id", "1"},
                {"client_secret", "secret"},
            };
 
        var response = await client.PostAsync("http://localhost:4746/token",
            new FormUrlEncodedContent(post));
        if (response.IsSuccessStatusCode)
        {
            var content = await response.Content.ReadAsStringAsync();
 
            var json = JObject.Parse(content);
            return json["access_token"].ToString();
        }
        throw new InvalidOperationException(response.ReasonPhrase);
    }
}
 
private async static Task<string> CallService(string token)
{
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", token);
 
        return await client.GetStringAsync("http://localhost:4746/api/data");
    }
}