Skip to content

Latest commit

 

History

History
591 lines (401 loc) · 39.8 KB

additional-claims.md

File metadata and controls

591 lines (401 loc) · 39.8 KB
title author description monikerRange ms.author ms.custom ms.date uid
Persist additional claims and tokens from external providers in ASP.NET Core
rick-anderson
Learn how to establish additional claims and tokens from external providers.
>= aspnetcore-2.1
riande
mvc
02/18/2021
security/authentication/social/additional-claims

Persist additional claims and tokens from external providers in ASP.NET Core

:::moniker range=">= aspnetcore-6.0"

An ASP.NET Core app can establish additional claims and tokens from external authentication providers, such as Facebook, Google, Microsoft, and Twitter. Each provider reveals different information about users on its platform, but the pattern for receiving and transforming user data into additional claims is the same.

Prerequisites

Decide which external authentication providers to support in the app. For each provider, register the app and obtain a client ID and client secret. For more information, see xref:security/authentication/social/index. The sample app uses the Google authentication provider.

Set the client ID and client secret

The OAuth authentication provider establishes a trust relationship with an app using a client ID and client secret. Client ID and client secret values are created for the app by the external authentication provider when the app is registered with the provider. Each external provider that the app uses must be configured independently with the provider's client ID and client secret. For more information, see the external authentication provider topics that apply:

  • Facebook authentication
  • Google authentication
  • Microsoft authentication
  • Twitter authentication
  • Other authentication providers
  • OpenIdConnect

Optional claims sent in the ID or access token from the authentication provider are usually configured in the provider's online portal. For example, Microsoft Entra ID permits assigning optional claims to the app's ID token in the app registration's Token configuration blade. For more information, see How to: Provide optional claims to your app (Azure documentation). For other providers, consult their external documentation sets.

The sample app configures the Google authentication provider with a client ID and client secret provided by Google:

[!code-csharp]

Establish the authentication scope

Specify the list of permissions to retrieve from the provider by specifying the xref:Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions.Scope*. Authentication scopes for common external providers appear in the following table.

Provider Scope
Facebook https://www.facebook.com/dialog/oauth
Google profile, email, openid
Microsoft https://login.microsoftonline.com/common/oauth2/v2.0/authorize
Twitter https://api.twitter.com/oauth/authenticate

In the sample app, Google's profile, email, and openid scopes are automatically added by the framework when xref:Microsoft.Extensions.DependencyInjection.GoogleExtensions.AddGoogle%2A is called on the xref:Microsoft.AspNetCore.Authentication.AuthenticationBuilder. If the app requires additional scopes, add them to the options. In the following example, the Google https://www.googleapis.com/auth/user.birthday.read scope is added to retrieve a user's birthday:

options.Scope.Add("https://www.googleapis.com/auth/user.birthday.read");

Map user data keys and create claims

In the provider's options, specify a xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.MapJsonKey* or xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.MapJsonSubKey* for each key or subkey in the external provider's JSON user data for the app identity to read on sign in. For more information on claim types, see xref:System.Security.Claims.ClaimTypes.

The sample app creates locale (urn:google:locale) and picture (urn:google:picture) claims from the locale and picture keys in Google user data:

[!code-csharp]

In Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal.ExternalLoginModel.OnPostConfirmationAsync, an xref:Microsoft.AspNetCore.Identity.IdentityUser (ApplicationUser) is signed into the app with xref:Microsoft.AspNetCore.Identity.SignInManager%601.SignInAsync*. During the sign in process, the xref:Microsoft.AspNetCore.Identity.UserManager%601 can store an ApplicationUser claims for user data available from the xref:Microsoft.AspNetCore.Identity.ExternalLoginInfo.Principal*.

In the sample app, OnPostConfirmationAsync (Account/ExternalLogin.cshtml.cs) establishes the locale (urn:google:locale) and picture (urn:google:picture) claims for the signed in ApplicationUser, including a claim for xref:System.Security.Claims.ClaimTypes.GivenName:

[!code-csharp]

By default, a user's claims are stored in the authentication cookie. If the authentication cookie is too large, it can cause the app to fail because:

  • The browser detects that the cookie header is too long.
  • The overall size of the request is too large.

If a large amount of user data is required for processing user requests:

  • Limit the number and size of user claims for request processing to only what the app requires.
  • Use a custom xref:Microsoft.AspNetCore.Authentication.Cookies.ITicketStore for the Cookie Authentication Middleware's xref:Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions.SessionStore to store identity across requests. Preserve large quantities of identity information on the server while only sending a small session identifier key to the client.

Save the access token

xref:Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions.SaveTokens* defines whether access and refresh tokens should be stored in the xref:Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties after a successful authorization. SaveTokens is set to false by default to reduce the size of the final authentication cookie.

The sample app sets the value of SaveTokens to true in xref:Microsoft.AspNetCore.Authentication.Google.GoogleOptions:

[!code-csharp]

When OnPostConfirmationAsync executes, store the access token (ExternalLoginInfo.AuthenticationTokens) from the external provider in the ApplicationUser's AuthenticationProperties.

The sample app saves the access token in OnPostConfirmationAsync (new user registration) and OnGetCallbackAsync (previously registered user) in Account/ExternalLogin.cshtml.cs:

[!code-csharp]

Note

For information on passing tokens to the Razor components of a server-side Blazor app, see xref:blazor/security/server/additional-scenarios#pass-tokens-to-a-server-side-blazor-app.

How to add additional custom tokens

To demonstrate how to add a custom token, which is stored as part of SaveTokens, the sample app adds an xref:Microsoft.AspNetCore.Authentication.AuthenticationToken with the current xref:System.DateTime for an AuthenticationToken.Name of TicketCreated:

[!code-csharp]

Create and add claims

The framework provides common actions and extension methods for creating and adding claims to the collection. For more information, see the xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions and xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionUniqueExtensions.

Users can define custom actions by deriving from xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction and implementing the abstract xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.Run* method.

For more information, see xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.

Add and update user claims

Claims are copied from external providers to the user database on first registration, not on sign in. If additional claims are enabled in an app after a user registers to use the app, call SignInManager.RefreshSignInAsync on a user to force the generation of a new authentication cookie.

In the Development environment working with test user accounts, delete and recreate the user account. For production systems, new claims added to the app can be backfilled into user accounts. After scaffolding the ExternalLogin page into the app at Areas/Pages/Identity/Account/Manage, add the following code to the ExternalLoginModel in the ExternalLogin.cshtml.cs file.

Add a dictionary of added claims. Use the dictionary keys to hold the claim types, and use the values to hold a default value. Add the following line to the top of the class. The following example assumes that one claim is added for the user's Google picture with a generic headshot image as the default value:

[!code-csharp]

Replace the default code of the OnGetCallbackAsync method with the following code. The code loops through the claims dictionary. Claims are added (backfilled) or updated for each user. When claims are added or updated, the user sign-in is refreshed using the xref:Microsoft.AspNetCore.Identity.SignInManager%601, preserving the existing authentication properties (AuthenticationProperties).

[!code-csharp]

A similar approach is taken when claims change while a user is signed in but a backfill step isn't required. To update a user's claims, call the following on the user:

  • UserManager.ReplaceClaimAsync on the user for claims stored in the identity database.
  • SignInManager.RefreshSignInAsync on the user to force the generation of a new authentication cookie.

Remove claim actions and claims

ClaimActionCollection.Remove(String) removes all claim actions for the given xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.ClaimType from the collection. ClaimActionCollectionMapExtensions.DeleteClaim(ClaimActionCollection, String) deletes a claim of the given xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.ClaimType from the identity. xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.DeleteClaim* is primarily used with OpenID Connect (OIDC) to remove protocol-generated claims.

Sample app output

Run the sample app and select the MyClaims link:

User Claims

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
    9b342344f-7aab-43c2-1ac1-ba75912ca999
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    someone@gmail.com
AspNet.Identity.SecurityStamp
    7D4312MOWRYYBFI1KXRPHGOSTBVWSFDE
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
    Judy
urn:google:locale
    en
urn:google:picture
    https://lh4.googleusercontent.com/-XXXXXX/XXXXXX/XXXXXX/XXXXXX/photo.jpg

Authentication Properties

.Token.access_token
    yc23.AlvoZqz56...1lxltXV7D-ZWP9
.Token.token_type
    Bearer
.Token.expires_at
    2019-04-11T22:14:51.0000000+00:00
.Token.TicketCreated
    4/11/2019 9:14:52 PM
.TokenNames
    access_token;token_type;expires_at;TicketCreated
.persistent
.issued
    Thu, 11 Apr 2019 20:51:06 GMT
.expires
    Thu, 25 Apr 2019 20:51:06 GMT

[!INCLUDEForward request information when behind a proxy or load balancer section]

View or download sample code (how to download)

:::moniker-end

:::moniker range=">= aspnetcore-3.0 < aspnetcore-6.0"

An ASP.NET Core app can establish additional claims and tokens from external authentication providers, such as Facebook, Google, Microsoft, and Twitter. Each provider reveals different information about users on its platform, but the pattern for receiving and transforming user data into additional claims is the same.

View or download sample code (how to download)

Prerequisites

Decide which external authentication providers to support in the app. For each provider, register the app and obtain a client ID and client secret. For more information, see xref:security/authentication/social/index. The sample app uses the Google authentication provider.

Set the client ID and client secret

The OAuth authentication provider establishes a trust relationship with an app using a client ID and client secret. Client ID and client secret values are created for the app by the external authentication provider when the app is registered with the provider. Each external provider that the app uses must be configured independently with the provider's client ID and client secret. For more information, see the external authentication provider topics that apply to your scenario:

  • Facebook authentication
  • Google authentication
  • Microsoft authentication
  • Twitter authentication
  • Other authentication providers
  • OpenIdConnect

Optional claims sent in the ID or access token from the authentication provider are usually configured in the provider's online portal. For example, Microsoft Entra ID permits you to assign optional claims to the app's ID token in the app registration's Token configuration blade. For more information, see How to: Provide optional claims to your app (Azure documentation). For other providers, consult their external documentation sets.

The sample app configures the Google authentication provider with a client ID and client secret provided by Google:

[!code-csharp]

Establish the authentication scope

Specify the list of permissions to retrieve from the provider by specifying the xref:Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions.Scope*. Authentication scopes for common external providers appear in the following table.

Provider Scope
Facebook https://www.facebook.com/dialog/oauth
Google profile, email, openid
Microsoft https://login.microsoftonline.com/common/oauth2/v2.0/authorize
Twitter https://api.twitter.com/oauth/authenticate

In the sample app, Google's profile, email, and openid scopes are automatically added by the framework when xref:Microsoft.Extensions.DependencyInjection.GoogleExtensions.AddGoogle%2A is called on the xref:Microsoft.AspNetCore.Authentication.AuthenticationBuilder. If the app requires additional scopes, add them to the options. In the following example, the Google https://www.googleapis.com/auth/user.birthday.read scope is added to retrieve a user's birthday:

options.Scope.Add("https://www.googleapis.com/auth/user.birthday.read");

Map user data keys and create claims

In the provider's options, specify a xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.MapJsonKey* or xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.MapJsonSubKey* for each key/subkey in the external provider's JSON user data for the app identity to read on sign in. For more information on claim types, see xref:System.Security.Claims.ClaimTypes.

The sample app creates locale (urn:google:locale) and picture (urn:google:picture) claims from the locale and picture keys in Google user data:

[!code-csharp]

In Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal.ExternalLoginModel.OnPostConfirmationAsync, an xref:Microsoft.AspNetCore.Identity.IdentityUser (ApplicationUser) is signed into the app with xref:Microsoft.AspNetCore.Identity.SignInManager%601.SignInAsync*. During the sign in process, the xref:Microsoft.AspNetCore.Identity.UserManager%601 can store an ApplicationUser claims for user data available from the xref:Microsoft.AspNetCore.Identity.ExternalLoginInfo.Principal*.

In the sample app, OnPostConfirmationAsync (Account/ExternalLogin.cshtml.cs) establishes the locale (urn:google:locale) and picture (urn:google:picture) claims for the signed in ApplicationUser, including a claim for xref:System.Security.Claims.ClaimTypes.GivenName:

[!code-csharp]

By default, a user's claims are stored in the authentication cookie. If the authentication cookie is too large, it can cause the app to fail because:

  • The browser detects that the cookie header is too long.
  • The overall size of the request is too large.

If a large amount of user data is required for processing user requests:

  • Limit the number and size of user claims for request processing to only what the app requires.
  • Use a custom xref:Microsoft.AspNetCore.Authentication.Cookies.ITicketStore for the Cookie Authentication Middleware's xref:Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions.SessionStore to store identity across requests. Preserve large quantities of identity information on the server while only sending a small session identifier key to the client.

Save the access token

xref:Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions.SaveTokens* defines whether access and refresh tokens should be stored in the xref:Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties after a successful authorization. SaveTokens is set to false by default to reduce the size of the final authentication cookie.

The sample app sets the value of SaveTokens to true in xref:Microsoft.AspNetCore.Authentication.Google.GoogleOptions:

[!code-csharp]

When OnPostConfirmationAsync executes, store the access token (ExternalLoginInfo.AuthenticationTokens) from the external provider in the ApplicationUser's AuthenticationProperties.

The sample app saves the access token in OnPostConfirmationAsync (new user registration) and OnGetCallbackAsync (previously registered user) in Account/ExternalLogin.cshtml.cs:

[!code-csharp]

Note

For information on passing tokens to the Razor components of a server-side Blazor app, see xref:blazor/security/server/additional-scenarios#pass-tokens-to-a-server-side-blazor-app.

How to add additional custom tokens

To demonstrate how to add a custom token, which is stored as part of SaveTokens, the sample app adds an xref:Microsoft.AspNetCore.Authentication.AuthenticationToken with the current xref:System.DateTime for an AuthenticationToken.Name of TicketCreated:

[!code-csharp]

Creating and adding claims

The framework provides common actions and extension methods for creating and adding claims to the collection. For more information, see the xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions and xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionUniqueExtensions.

Users can define custom actions by deriving from xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction and implementing the abstract xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.Run* method.

For more information, see xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.

Add and update user claims

Claims are copied from external providers to the user database on first registration, not on sign in. If additional claims are enabled in an app after a user registers to use the app, call SignInManager.RefreshSignInAsync on a user to force the generation of a new authentication cookie.

In the Development environment working with test user accounts, you can simply delete and recreate the user account. For production systems, new claims added to the app can be backfilled into user accounts. After scaffolding the ExternalLogin page into the app at Areas/Pages/Identity/Account/Manage, add the following code to the ExternalLoginModel in the ExternalLogin.cshtml.cs file.

Add a dictionary of added claims. Use the dictionary keys to hold the claim types, and use the values to hold a default value. Add the following line to the top of the class. The following example assumes that one claim is added for the user's Google picture with a generic headshot image as the default value:

private readonly IReadOnlyDictionary<string, string> _claimsToSync = 
    new Dictionary<string, string>()
    {
        { "urn:google:picture", "https://localhost:5001/headshot.png" },
    };

Replace the default code of the OnGetCallbackAsync method with the following code. The code loops through the claims dictionary. Claims are added (backfilled) or updated for each user. When claims are added or updated, the user sign-in is refreshed using the xref:Microsoft.AspNetCore.Identity.SignInManager%601, preserving the existing authentication properties (AuthenticationProperties).

public async Task<IActionResult> OnGetCallbackAsync(
    string returnUrl = null, string remoteError = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (remoteError != null)
    {
        ErrorMessage = $"Error from external provider: {remoteError}";

        return RedirectToPage("./Login", new {ReturnUrl = returnUrl });
    }

    var info = await _signInManager.GetExternalLoginInfoAsync();

    if (info == null)
    {
        ErrorMessage = "Error loading external login information.";
        return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
    }

    // Sign in the user with this external login provider if the user already has a 
    // login.
    var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, 
        info.ProviderKey, isPersistent: false, bypassTwoFactor : true);

    if (result.Succeeded)
    {
        _logger.LogInformation("{Name} logged in with {LoginProvider} provider.", 
            info.Principal.Identity.Name, info.LoginProvider);

        if (_claimsToSync.Count > 0)
        {
            var user = await _userManager.FindByLoginAsync(info.LoginProvider, 
                info.ProviderKey);
            var userClaims = await _userManager.GetClaimsAsync(user);
            bool refreshSignIn = false;

            foreach (var addedClaim in _claimsToSync)
            {
                var userClaim = userClaims
                    .FirstOrDefault(c => c.Type == addedClaim.Key);

                if (info.Principal.HasClaim(c => c.Type == addedClaim.Key))
                {
                    var externalClaim = info.Principal.FindFirst(addedClaim.Key);

                    if (userClaim == null)
                    {
                        await _userManager.AddClaimAsync(user, 
                            new Claim(addedClaim.Key, externalClaim.Value));
                        refreshSignIn = true;
                    }
                    else if (userClaim.Value != externalClaim.Value)
                    {
                        await _userManager
                            .ReplaceClaimAsync(user, userClaim, externalClaim);
                        refreshSignIn = true;
                    }
                }
                else if (userClaim == null)
                {
                    // Fill with a default value
                    await _userManager.AddClaimAsync(user, new Claim(addedClaim.Key, 
                        addedClaim.Value));
                    refreshSignIn = true;
                }
            }

            if (refreshSignIn)
            {
                await _signInManager.RefreshSignInAsync(user);
            }
        }

        return LocalRedirect(returnUrl);
    }

    if (result.IsLockedOut)
    {
        return RedirectToPage("./Lockout");
    }
    else
    {
        // If the user does not have an account, then ask the user to create an 
        // account.
        ReturnUrl = returnUrl;
        ProviderDisplayName = info.ProviderDisplayName;

        if (info.Principal.HasClaim(c => c.Type == ClaimTypes.Email))
        {
            Input = new InputModel
            {
                Email = info.Principal.FindFirstValue(ClaimTypes.Email)
            };
        }

        return Page();
    }
}

A similar approach is taken when claims change while a user is signed in but a backfill step isn't required. To update a user's claims, call the following on the user:

  • UserManager.ReplaceClaimAsync on the user for claims stored in the identity database.
  • SignInManager.RefreshSignInAsync on the user to force the generation of a new authentication cookie.

Removal of claim actions and claims

ClaimActionCollection.Remove(String) removes all claim actions for the given xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.ClaimType from the collection. ClaimActionCollectionMapExtensions.DeleteClaim(ClaimActionCollection, String) deletes a claim of the given xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.ClaimType from the identity. xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.DeleteClaim* is primarily used with OpenID Connect (OIDC) to remove protocol-generated claims.

Sample app output

User Claims

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
    9b342344f-7aab-43c2-1ac1-ba75912ca999
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    someone@gmail.com
AspNet.Identity.SecurityStamp
    7D4312MOWRYYBFI1KXRPHGOSTBVWSFDE
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
    Judy
urn:google:locale
    en
urn:google:picture
    https://lh4.googleusercontent.com/-XXXXXX/XXXXXX/XXXXXX/XXXXXX/photo.jpg

Authentication Properties

.Token.access_token
    yc23.AlvoZqz56...1lxltXV7D-ZWP9
.Token.token_type
    Bearer
.Token.expires_at
    2019-04-11T22:14:51.0000000+00:00
.Token.TicketCreated
    4/11/2019 9:14:52 PM
.TokenNames
    access_token;token_type;expires_at;TicketCreated
.persistent
.issued
    Thu, 11 Apr 2019 20:51:06 GMT
.expires
    Thu, 25 Apr 2019 20:51:06 GMT

[!INCLUDEForward request information when behind a proxy or load balancer section]

:::moniker-end

:::moniker range="< aspnetcore-3.0"

An ASP.NET Core app can establish additional claims and tokens from external authentication providers, such as Facebook, Google, Microsoft, and Twitter. Each provider reveals different information about users on its platform, but the pattern for receiving and transforming user data into additional claims is the same.

View or download sample code (how to download)

Prerequisites

Decide which external authentication providers to support in the app. For each provider, register the app and obtain a client ID and client secret. For more information, see xref:security/authentication/social/index. The sample app uses the Google authentication provider.

Set the client ID and client secret

The OAuth authentication provider establishes a trust relationship with an app using a client ID and client secret. Client ID and client secret values are created for the app by the external authentication provider when the app is registered with the provider. Each external provider that the app uses must be configured independently with the provider's client ID and client secret. For more information, see the external authentication provider topics that apply to your scenario:

  • Facebook authentication
  • Google authentication
  • Microsoft authentication
  • Twitter authentication
  • Other authentication providers
  • OpenIdConnect

The sample app configures the Google authentication provider with a client ID and client secret provided by Google:

[!code-csharp]

Establish the authentication scope

Specify the list of permissions to retrieve from the provider by specifying the xref:Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions.Scope*. Authentication scopes for common external providers appear in the following table.

Provider Scope
Facebook https://www.facebook.com/dialog/oauth
Google https://www.googleapis.com/auth/userinfo.profile
Microsoft https://login.microsoftonline.com/common/oauth2/v2.0/authorize
Twitter https://api.twitter.com/oauth/authenticate

In the sample app, Google's userinfo.profile scope is automatically added by the framework when xref:Microsoft.Extensions.DependencyInjection.GoogleExtensions.AddGoogle* is called on the xref:Microsoft.AspNetCore.Authentication.AuthenticationBuilder. If the app requires additional scopes, add them to the options. In the following example, the Google https://www.googleapis.com/auth/user.birthday.read scope is added in order to retrieve a user's birthday:

options.Scope.Add("https://www.googleapis.com/auth/user.birthday.read");

Map user data keys and create claims

In the provider's options, specify a xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.MapJsonKey* or xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.MapJsonSubKey* for each key/subkey in the external provider's JSON user data for the app identity to read on sign in. For more information on claim types, see xref:System.Security.Claims.ClaimTypes.

The sample app creates locale (urn:google:locale) and picture (urn:google:picture) claims from the locale and picture keys in Google user data:

[!code-csharp]

In Microsoft.AspNetCore.Identity.UI.Pages.Account.Internal.ExternalLoginModel.OnPostConfirmationAsync, an xref:Microsoft.AspNetCore.Identity.IdentityUser (ApplicationUser) is signed into the app with xref:Microsoft.AspNetCore.Identity.SignInManager%601.SignInAsync*. During the sign in process, the xref:Microsoft.AspNetCore.Identity.UserManager%601 can store an ApplicationUser claims for user data available from the xref:Microsoft.AspNetCore.Identity.ExternalLoginInfo.Principal*.

In the sample app, OnPostConfirmationAsync (Account/ExternalLogin.cshtml.cs) establishes the locale (urn:google:locale) and picture (urn:google:picture) claims for the signed in ApplicationUser, including a claim for xref:System.Security.Claims.ClaimTypes.GivenName:

[!code-csharp]

By default, a user's claims are stored in the authentication cookie. If the authentication cookie is too large, it can cause the app to fail because:

  • The browser detects that the cookie header is too long.
  • The overall size of the request is too large.

If a large amount of user data is required for processing user requests:

  • Limit the number and size of user claims for request processing to only what the app requires.
  • Use a custom xref:Microsoft.AspNetCore.Authentication.Cookies.ITicketStore for the Cookie Authentication Middleware's xref:Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions.SessionStore to store identity across requests. Preserve large quantities of identity information on the server while only sending a small session identifier key to the client.

Save the access token

xref:Microsoft.AspNetCore.Authentication.RemoteAuthenticationOptions.SaveTokens* defines whether access and refresh tokens should be stored in the xref:Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties after a successful authorization. SaveTokens is set to false by default to reduce the size of the final authentication cookie.

The sample app sets the value of SaveTokens to true in xref:Microsoft.AspNetCore.Authentication.Google.GoogleOptions:

[!code-csharp]

When OnPostConfirmationAsync executes, store the access token (ExternalLoginInfo.AuthenticationTokens) from the external provider in the ApplicationUser's AuthenticationProperties.

The sample app saves the access token in OnPostConfirmationAsync (new user registration) and OnGetCallbackAsync (previously registered user) in Account/ExternalLogin.cshtml.cs:

[!code-csharp]

How to add additional custom tokens

To demonstrate how to add a custom token, which is stored as part of SaveTokens, the sample app adds an xref:Microsoft.AspNetCore.Authentication.AuthenticationToken with the current xref:System.DateTime for an AuthenticationToken.Name of TicketCreated:

[!code-csharp]

Creating and adding claims

The framework provides common actions and extension methods for creating and adding claims to the collection. For more information, see the xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions and xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionUniqueExtensions.

Users can define custom actions by deriving from xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction and implementing the abstract xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.Run* method.

For more information, see xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.

Removal of claim actions and claims

ClaimActionCollection.Remove(String) removes all claim actions for the given xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.ClaimType from the collection. ClaimActionCollectionMapExtensions.DeleteClaim(ClaimActionCollection, String) deletes a claim of the given xref:Microsoft.AspNetCore.Authentication.OAuth.Claims.ClaimAction.ClaimType from the identity. xref:Microsoft.AspNetCore.Authentication.ClaimActionCollectionMapExtensions.DeleteClaim* is primarily used with OpenID Connect (OIDC) to remove protocol-generated claims.

Sample app output

User Claims

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
    9b342344f-7aab-43c2-1ac1-ba75912ca999
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
    someone@gmail.com
AspNet.Identity.SecurityStamp
    7D4312MOWRYYBFI1KXRPHGOSTBVWSFDE
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
    Judy
urn:google:locale
    en
urn:google:picture
    https://lh4.googleusercontent.com/-XXXXXX/XXXXXX/XXXXXX/XXXXXX/photo.jpg

Authentication Properties

.Token.access_token
    yc23.AlvoZqz56...1lxltXV7D-ZWP9
.Token.token_type
    Bearer
.Token.expires_at
    2019-04-11T22:14:51.0000000+00:00
.Token.TicketCreated
    4/11/2019 9:14:52 PM
.TokenNames
    access_token;token_type;expires_at;TicketCreated
.persistent
.issued
    Thu, 11 Apr 2019 20:51:06 GMT
.expires
    Thu, 25 Apr 2019 20:51:06 GMT

[!INCLUDEForward request information when behind a proxy or load balancer section]

:::moniker-end

Additional resources

  • dotnet/AspNetCore engineering SocialSample app: The linked sample app is on the dotnet/AspNetCore GitHub repo's main engineering branch. The main branch contains code under active development for the next release of ASP.NET Core. To see a version of the sample app for a released version of ASP.NET Core, use the Branch drop down list to select a release branch (for example release/{X.Y}).