Web App Roles - ob1dev/Auth0 GitHub Wiki

The last step to configure the Web App is adding authorization. After Auth0 checks a user identity and returns the token with claims, a user gets authenticated in the app. But what can s\he do inside the app? This is what authorization can answer on.

The idea here is that different users or better to say group of users do different stuff inside the app. For this purpose, you need to define roles. Where each role will grand different access rights to users.

I used a hardcoded list of the roles viewer, editor and admin. And I assigned one of these roles to the following users, which I defined in Auth0.

User Role
[email protected] viewer
[email protected] editor
[email protected] admin

To keep information which role(s) is assigned to the above users, you will use Auth0 Metadata.

IMPORTANT

You don't have to hardcode users and/or roles. In Auth0 you can dynamically create custom roles and assign them to users using Auth0 Rules or Management API.

Auth0 Portal

Users and Roles

Log in to Auth0 Portal, and then go to the section Users at the right menu. Click the button + Create Your First User or + Create User if you have already created some user(s).

After you're done with creating three users, go through each of them and add a custom metadata.

So, click on a user, then switch to the tab Details and scroll down to the section Metadata. Add a new entry roles and assigned one of the roles (viewer, editor and admin).

Now you have users with assigned roles, but how to push this information back to Web App? The app_metadata that includes roles is not a standard claim of the token openid. Well, the token supports standard claims as well as custom ones. You need Auth0 Rules to add a custom claim to your ID Token.

Rules

In the Auth0 Portal, go to the section Rules at the right menu. Click the button _+ Create your First Rule _ or + Create Rule if you have already created some rule(s).

Use the template empty rule and add the following code.

function (user, context, callback)
{
  var metadata = user.app_metadata || {};
 
  console.log("Setting role(s) for user \'" + user.email + "\' (" + metadata.roles + ")");
   
  if (!metadata.roles)
  {
    console.log("The user \'" + user.email + "\' has no role. Access denied.");
    return callback(new UnauthorizedError("No roles defined. Access denied."));
  }

  context.idToken["https://olegburov.com/roles"] = metadata.roles;
    
  callback(null, user, context);   
}

NOTE

The https://olegburov.com/roles is just a namespace for a custom claim. It could be whatever you want, unless it intersects with existent claim.

IMPORTANT

If something doesn't work the way you expected, use the extension Real-time Webtask Logs to debug Auth0 Rules. Click the button Install Real-Time Logs or go the section Extensions and search for it there.

Visual Studio

Map custom claim

In the file Startup.cs, modify the method ConfigureServices as shown below to tell the OpenID Connect middleware, which claim has the roles.

public void ConfigureServices(IServiceCollection services)
{
...
  options.TokenValidationParameters = new TokenValidationParameters
  {
  ...
    RoleClaimType = "https://olegburov.com/roles"
  };
...
}  

Add view

Create a new view AccessDenied under the folder Views\Account, to render it for a user, which isn't authorized or don't have a required role (access right).

@{
  ViewData["Title"] = "Access Denied";
}

<h2>Access</h2>
<h4>Denied</h4>
<hr />

<p class="text-danger">You do not have access to this resource.</p>

Modify Account Controller

Modify the class AccountController under the folder Controllers, by adding a new action AccessDenied and decorating the actions Signout and Profile with attribute Authorize. The Authorize will restrict access to these actions unless a user is both authenticated and authorized. In this case, it doesn't matter which roles a user is authorized.

[Route("[controller]/[action]")]
public class AccountController : Controller
{
...
  [Authorize]
  public async Task Signout()
  {
  ...
  }

  [Authorize]
  public async Task<IActionResult> Profile()
  {
  ...
  }

  public IActionResult AccessDenied()
  {
    return View();
  }
}

NOTE

For more information about the attribute Authorize read here.

Modify Home controller

Modify the class HomeController under the folder Controllers, by decorating the actions with attribute Authorize. Just like you did before for in the class AccountController, but this time using specific roles.

public class HomeController : Controller
{
  ...
  [HttpGet]
  [Authorize(Roles = "admin, editor")]
  public IActionResult New()
  {
  ...
  }

  [HttpPost]
  [Authorize(Roles = "admin, editor")]
  public async Task<IActionResult> New(RepositoryModel repository)
  {
  ...
  }

  [HttpGet]
  [Authorize(Roles = "admin, editor")]
  public async Task<IActionResult> Edit(Guid id)
  {
  ...
  }

  [HttpPost]
  [Authorize(Roles = "admin, editor")]
  public async Task<IActionResult> Edit(RepositoryModel repository)
  {
  ...
  }

  [Authorize(Roles = "admin")]
  public async Task<IActionResult> Delete(Guid id)
  {
  ...
  }
...
}

Modify Index view

Let's say you want to show some menu items or buttons or simple a piece of HTML to a user with specific role. You still can do this even with Razor Views.

...
@if (!User.Identity.IsAuthenticated)
{
  <div class="row">
    <div class="col-md-12">
      <h2>Please log in to get started</h2>
      ...
    </div>
  </div>
}
else
{
...
  @if (User.IsInRole("admin") || User.IsInRole("editor"))
  {
    <a class="btn btn-success" asp-action="New">
      <span class="glyphicon glyphicon-book" aria-hidden="true"></span>
      New
    </a>
  }
  <table class="table">
  ...
    <td>
      <div class="btn-group" role="group" aria-label="Operations">
        @if (User.IsInRole("admin") || User.IsInRole("editor"))
        {
          <a class="btn btn-default" asp-action="Edit" asp-route-id="@item.Id">Edit</a>
        }
        @if (User.IsInRole("admin"))
        {
          <a class="btn btn-danger" asp-action="Delete" asp-route-id="@item.Id">Delete</a>
        }
      </div>
    </td>
  ...
  </table>
}

Summary

You've now used data to protect pages based on user's role, which Web App obtains from Auth0. In the following tutorial, you'll learn more about accessing a user's related data.

What's next?

Creating API in Auth0 portal

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