'RFC - Adding Group Claims from OKTA to Role Claims in .net Framework Using OIDC
PROBLEM: The suggested method by Lee Brandt see: https://developer.okta.com/blog/2018/04/18/authorization-in-your-aspnet-mvc-4-application was not working due to notifications not being invoked. After a number of days researching and attempting various options, I came up with following solution.
UPDATE: it was a spelling error that it was not being called. duh.
But the solution I have seems to be easier.
Solution 1:[1]
BEHAVIOUR
It may be OK, though the standard behavior is all built around creating or restoring a useful ClaimsPrincipal. The Microsoft code does this:
When there is no auth cookie, do the OIDC redirect to sign the user in, to eventually get tokens
Create a ClaimsPrincipal from the ID token, then serialize tokens to an encrypted HTTP only cookie
On all subsequent requests, the stack just deserializes the ClaimsPrincipal from the ID token in the cookie
Occasionally a token refresh may occur, which also rewrites the cookie, to store new tokens
CLAIMS PRINCIPAL CUSTOMIZATION
AddOpenIDConnect
has an options object with a property called TokenValidationParameters
. This has a RoleClaimType
which could be set to Groups
in your case.
It is recommended to customize claims programmatically when tokens are first received, so your custom code is fine - though it should only run when there is no auth cookie yet.
There has always been an action such as OnTokenValidated for customizing the ClaimsPrincipal. I first used this in around 2014 with the .Net framework and it has not really changed since. It occurs after the ID token is validated and before the ClaimsPrincipal is finalized. Ideally put your code here.
Solution 2:[2]
SOLUTION
Setup OKTA using procedure in Lee's article.
In Startup.cs, instead of using 'UseOpenIdConnectAuthentication' use:
app.UseCookieAuthentication(...);
app.UseOktaMvc(...**
app.Use(async (context, next) =>
{
if (context.Authentication.User.Identity.IsAuthenticated)
{
// Get claims from access_token
var accessToken =
((ClaimsIdentity)context.Authentication.User.Identity)
.Claims
.Where(x => x.Type == "access_token")
.FirstOrDefault().Value;
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadJwtToken(accessToken);
// Add roles from claims
var claims = new List<Claim>();
foreach (var group in token.Claims
.Where(x => x.Type == "allgroups"))
{
claims.Add(new Claim(ClaimTypes.Role, group.Value));
}
if (claims.Count > 0)
{
var identity = new ClaimsIdentity();
identity.AddClaims(claims);
var identities = new List<ClaimsIdentity> { identity };
context.Authentication.User.AddIdentities(identities);
}
}
await next.Invoke();
});
The OKTA Groups claims are added as Role claims allowing the controller authorize attributes to be utilized.
However, I notice when I reload the page the claims are not retained but must be re-added. Is this correct?
Any suggestions or problems?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Gary Archer |
Solution 2 |