Web App Profile - ob1dev/Auth0 GitHub Wiki

Okay, at this point the Web App can sing in and sign out a user. The next step is to add some details about authenticated user.

Previously the Web App asked Auth0 for the scope openid only. As a result, it got the token id_token with information to use the OpenID Connect protocol to verify the identity of a user. To be more specific, if the scope is set to openid, then the token id_token will contain the following claims:

{
  "iss": "Issuer Identifier for the Issuer of the response.",
  "sub": "Subject Identifier.",
  "aud": "Audience(s) that this ID Token is intended for.",
  "exp": "Expiration time on or after which the ID Token MUST NOT be accepted for processing.",
  "iat": "Time at which the JWT was issued."
}

NOTE

For more information about ID Token, see its specification here.

IMPORTANT

The Auth0 doesn't return a naked token. It wraps a token into a digitally signed self-container aka JSON Web Token format (JWT). Such token can't be easily read or modified by 3rd parties, because it needs to be decoded/encoded using a trusted certificate. You can read more about JWT here, as well as decode a token.

NOTE

For more information about Auth0 ID Token wrapped into JWT, read here.

Visual Studio

Add scopes

Now we need the Web App to ask for additional scopes such as profile and email. As a result, the token id_token will contain the following claims in addition to the iss, sub, aud, exp and iat ones.

Scope profile:

{
  "name": "End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences.", 
  "family_name": "Surname(s) or last name(s) of the End-User.", 
  "given_name": "Given name(s) or first name(s) of the End-User.",
  "middle_name": "Middle name(s) of the End-User.",
  "nickname": "Casual name of the End-User that may or may not be the same as the given_name.",
  "preferred_username": "Shorthand name by which the End-User wishes to be referred to at the RP.",
  "profile": "URL of the End-User's profile page.",
  "picture": "Note that this URL SHOULD specifically reference a profile photo of the End-User suitable for displaying when describing the End-User, rather than an arbitrary photo taken by the End-User.",
  "website": "URL of the End-User's Web page or blog.",
  "gender": "End-User's gender.",
  "birthdate": "End-User's birthday, represented as an ISO 8601:2004 [ISO8601‑2004] YYYY-MM-DD format.",
  "zoneinfo": "String from zoneinfo zoneinfo time zone database representing the End-User's time zone.",
  "locale": "End-User's locale, represented as a BCP47 RFC5646 language tag.",
  "updated_at": "Time the End-User's information was last updated."
}

Scope email:

{
  "email": "End-User's preferred e-mail address.",
  "email_verified": "True if the End-User's e-mail address has been verified; otherwise false."
}

In the file Startup.cs, modify the method ConfigureServices as shown below.

public void ConfigureServices(IServiceCollection services)
{
...
  options.Scope.Clear();
  options.Scope.Add("openid");
  options.Scope.Add("profile");
  options.Scope.Add("email");
...
}

Additionally, I want the property User.Identity.Name returns whatever values has the claim nickmame in the returned token id_token. To make it that way, modify the method ConfigureServices with those lines.

public void ConfigureServices(IServiceCollection services)
{
...
  options.TokenValidationParameters = new TokenValidationParameters
  {
    NameClaimType = "nickname",
  };
...
}

Modify Login partial view

Modify partial view _LoginPartial under the folder Views\Shared, to render a user's name and picture, as well as a link to profile page, which you will add a bit later.

...
@using System.Security.Principal

@if (User.Identity.IsAuthenticated)
{
  <ul class="nav navbar-nav navbar-right">
    <li class="dropdown">
      <a class="dropdown-toggle" role="button" aria-expanded="false" aria-haspopup="true" href="#" data-toggle="dropdown">
        <img width="20" height="20" class="avatar" alt="@User.Identity.Name" src="@User.Claims.FirstOrDefault(c => c.Type == "picture")?.Value">
        <span class="caret"></span>
      </a>
      <ul class="dropdown-menu">
        <li class="dropdown-header header-nav-current-user">Signed in as <strong>@User.Identity.Name</strong></li>
        <li class="dropdown-divider" role="separator"></li>
        <li><a asp-controller="Account" asp-action="Profile">Your profile</a></li>
        <li><a asp-controller="Account" asp-action="Signout">Sign out</a></li>
      </ul>
    </li>
  </ul>
}
else
{
...
}

Add model

Create a new class UserProfileModel under the folder Models as shown below.

public class UserProfileModel
{
  public string EmailAddress { get; set; }
  public string Name { get; set; }
  public string ProfileImage { get; set; }
  public string IdToken { get; set; }
}

Add view

Create a new view Profile under the folder Views\Account, to render a user's profile.

@model OneGit.Web.Models.UserProfileModel
@{
  ViewData["Title"] = "Profile";
}

<h2>@ViewData["Title"]</h2>

<img class="img-rounded img-responsive" alt="@Model.Name" src="@Model.ProfileImage" />
<h3>@Model.Name</h3>
<p>
  <i class="glyphicon glyphicon-envelope"></i> <code>@Model.EmailAddress</code>
</p>
<p>
  <i class="glyphicon glyphicon-user"></i> <code>id_token</code>
  <div>
    <mark>@Model.IdToken</mark>
  </div>
</p>

Modify Account controller

Modify the class AccountController under the folder Controllers, by adding a new action Profile.

[Route("[controller]/[action]")]
public class AccountController : Controller
{
...
  [HttpGet]
  public async Task<IActionResult> Profile()
  {
    return View(new UserProfileModel()
    {
      Name = User.Identity.Name,
      EmailAddress = User.Claims.FirstOrDefault(c => c.Type == "name")?.Value,
      ProfileImage = User.Claims.FirstOrDefault(c => c.Type == "picture")?.Value,
      IdToken = await HttpContext.GetTokenAsync("id_token")
    });
  }
}

IMPORTANT

As you can see, the model is populated using claims, as well as the value of the id_token itself. The reason why I want to render the token, is because I want you to pass its encoded value to https://jwt.io/ and examine the decoded parts - Header (algorithm & token type), Payload (Data) and Verify Signature. If you add or remove scopes profile, email or other, you will see how the list of claims is changed in the section Payload.

Summary

You have now completed the integrating Auth0 with Web App. You have learned how to add additional scopes, such as profile and email to including more user's related data into the ID Token, as well as how to read claims from the token. In the next tutorial you'll expand the functionality by adding Auth0 API in addition to Auth Application.

What's next?

Web App - Roles

⚠️ **GitHub.com Fallback** ⚠️