Test role-based authorization with configurable test users
Give a handful of test users the roles you care about, sign in as each of them, and check that your app allows and denies the right things, using real tokens shaped like your production identity provider's.
The problem
Access control bugs hide in the combinations: the admin who can't see a page, the reader who can delete. Testing them against a real identity provider means creating accounts, assigning roles through a directory admin, and remembering passwords. As a result, most teams test one role well and the rest barely.
Why HeyIdentity fits
- Users are part of the configuration: a key, a display name and any claims you like, including
roles. - Claim values keep their JSON type, so
["Admin", "User"]arrives as an array and"Admin"as a string, whichever your app expects. - Changing a user's roles takes effect on their next sign-in. You don't need to redeploy anything.
- The Generic profile can put roles where your production provider does, so your role mapping code is tested as well.
Set it up
- Sign up and open your management link.
- Under Users, add one user per role combination you want to test, for example:
admin "Avery Admin" roles: ["Admin", "User"] user "Riley User" roles: ["User"] auditor "Ana Auditor" roles: ["Auditor"] nobody "No Roles" (no roles claim) - In Settings, match your production token shape. The roles claim name defaults to
roles. Set a nested key for providers that nest roles, for example claimrealm_accesswith nested keyrolesfor Keycloak-style tokens. The Microsoft profile keepsrolesat the top level, as Entra ID does; configure roles as an array to match Entra's tokens. - Choose whether each claim goes into the ID token, the access token or both. APIs usually authorize on the access token, and web apps on the ID token.
ASP.NET Core
Keep the claim names as issued and tell ASP.NET Core which claim holds the roles:
.AddOpenIdConnect(options =>
{
options.Authority = "https://app.heyidentity.dev/t/{tenantRouteId}/c/{configurationId}";
options.ClientId = "my-app";
options.ClientSecret = "my-app-secret";
options.ResponseType = "code";
options.MapInboundClaims = false;
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "roles";
});
[Authorize(Roles = "Admin")]
public IActionResult AdminArea() => View();
For an API using JWT bearer authentication, set the same MapInboundClaims and RoleClaimType on AddJwtBearer. If you use a nested shape such as realm_access.roles, add an IClaimsTransformation that copies the nested values into role claims, the same code you would need in production.
Single-page apps
// With oidc-client-ts: the ID token claims are on user.profile
const user = await userManager.getUser();
const roles = [].concat(user?.profile.roles ?? []); // string or array
const canSeeAdmin = roles.includes('Admin');
The UI check is only a convenience. Keep enforcing roles in your API with the access token.
Verify it
- Sign in as
adminand open the protected page. It should be allowed. - Sign in as
userandnobody. The page should be denied, and your API should return 403. - Change
user's roles in the management page, sign in again, and confirm the decision follows. - See the same check without code in demo case B, which signs in as an admin or a regular user and shows the allow or deny decision.
Limitations
- Roles are static per user. There are no groups, directory lookups or role hierarchies; give each test user the exact roles your app expects.
- Already-issued tokens keep their roles until they expire or are refreshed.
- For development and testing only. Never use HeyIdentity to protect production identities.
Test every role, not just admin
Sign up to get a tenant and configure users for each role.