Skip to content

Commit

Permalink
populate id token when skipping consent screen
Browse files Browse the repository at this point in the history
  • Loading branch information
josxha committed Dec 29, 2023
1 parent 4dc7461 commit 1babed1
Showing 1 changed file with 47 additions and 42 deletions.
89 changes: 47 additions & 42 deletions KratosSelfService/Controllers/OAuth2Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,16 @@ public async Task<IActionResult> ConsentGet([FromQuery(Name = "consent_challenge
logger.LogDebug("Skipping consent request and accepting it.");

// Now it's time to grant the consent request. You could also deny the request if something went terribly wrong
var consentRequest = await oAuth2Api.AcceptOAuth2ConsentRequestAsync(challenge,
new HydraAcceptOAuth2ConsentRequest
{
// We can grant all scopes that have been requested - hydra already checked for
// us that no additional scopes are requested accidentally.
GrantScope = challengeRequest.RequestedScope,
// ORY Hydra checks if requested audiences are allowed by the client, so we can simply echo this.
GrantAccessTokenAudience = challengeRequest.RequestedAccessTokenAudience,
// The session allows us to set session data for id and access tokens
Session = new HydraAcceptOAuth2ConsentRequestSession()
});
var acceptRequest = await AcceptRequest(
challenge,
challengeRequest.RequestedScope,
challengeRequest.RequestedAccessTokenAudience,
false
);

logger.LogDebug("Consent request successfully accepted");
// All we need to do now is to redirect the user back to hydra
return Redirect(consentRequest.RedirectTo);
return Redirect(acceptRequest.RedirectTo);
}

[HttpPost("consent")]
Expand All @@ -56,10 +51,6 @@ public async Task<IActionResult> ConsentPost(
if (env.HydraAdminUrl == null) return NotFound();
var oAuth2Api = api.HydraOAuth2!;

// extractSession only gets the session data from the request
// You can extract more data from the Ory Identities admin API

// Let's fetch the consent request again to be able to set `grantAccessTokenAudience` properly.
// Let's see if the user decided to accept or reject the consent request.
if (action != "accept")
{
Expand All @@ -76,48 +67,66 @@ public async Task<IActionResult> ConsentPost(
}

// Let's fetch the consent request again to be able to set `grantAccessTokenAudience` properly.
// Let's see if the user decided to accept or reject the consent request.
logger.LogDebug("Consent request was accepted by the user");
var consentRequest = await oAuth2Api.GetOAuth2ConsentRequestAsync(challenge);

var acceptRequest = await AcceptRequest(
grantAccessTokenAudience: consentRequest.RequestedAccessTokenAudience,
grantScopes: grantScopes,
remember: remember,
challenge: challenge
);

// All we need to do now is to redirect the user back!
logger.LogDebug("Consent request successfully accepted, redirect to: {URL}", acceptRequest.RedirectTo);
return Redirect(acceptRequest.RedirectTo);
}

private async Task<HydraOAuth2RedirectTo> AcceptRequest(string challenge, List<string> grantScopes,
List<string> grantAccessTokenAudience, bool remember)
{
// extractSession only gets the session data from the request
// You can extract more data from the Ory Identities admin API
var kratosSession = HttpContext.GetSession()!;
var kratosTraits = (JObject)kratosSession.Identity.Traits;

// https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
var idToken = new JObject();

if (env.HydraTraitsMapping != null)
{
var list = env.HydraTraitsMapping.Split(",");
foreach (var entry in list)
foreach (var mapping in env.HydraTraitsMapping.Split(","))
{
var parts = entry.Split(":");
if (!grantScopes.Contains("email") || kratosTraits["email"] == null) continue;
var pathItems = parts[0].Split(".");
var traits = kratosTraits;
var success = true;
for (var i = 0; i < pathItems.Length - 1; i++)
if (traits[pathItems[i]] is JObject jObject)
var parts = mapping.Split(":");
var oidcClaim = parts[1];
if (!grantScopes.Contains(oidcClaim)) continue;

var traitPathSegments = parts[0].Split(".");
var tmpTraits = kratosTraits;
for (var i = 0; i < traitPathSegments.Length; i++)
{
// last index
if (i == traitPathSegments.Length - 1)
{
idToken[oidcClaim] = tmpTraits[traitPathSegments.Last()];
break;
}

// not last index
if (tmpTraits[traitPathSegments[i]] is JObject jObject)
{
traits = jObject;
tmpTraits = jObject;
}
else
{
success = false;
logger.LogError("Can't find identity trait {TraitPath}", parts[0]);
break;
}

if (success)
idToken[parts[1]] = traits[pathItems.Last()];
else
logger.LogError("Can't find identity trait {TraitPath}", parts[0]);
}
}
}

// The session allows us to set session data for id and access tokens
var hydraSession = new HydraAcceptOAuth2ConsentRequestSession(idToken: idToken);

var acceptRequest = await oAuth2Api.AcceptOAuth2ConsentRequestAsync(challenge,
return await api.HydraOAuth2!.AcceptOAuth2ConsentRequestAsync(challenge,
new HydraAcceptOAuth2ConsentRequest
{
// We can grant all scopes that have been requested - hydra already checked for us that no
Expand All @@ -130,18 +139,14 @@ public async Task<IActionResult> ConsentPost(
// If that variable is not set, the session will be used as-is.
Session = hydraSession,
// ORY Hydra checks if requested audiences are allowed by the client, so we can simply echo this.
GrantAccessTokenAudience = consentRequest.RequestedAccessTokenAudience,
GrantAccessTokenAudience = grantAccessTokenAudience,
// This tells hydra to remember this consent request and allow the same client to request the same
// scopes from the same user, without showing the UI, in the future.
Remember = remember,
// When this "remember" session expires, in seconds. Set this to 0 so it will never expire.
RememberFor = env.HydraRememberConsentSessionForSeconds,
HandledAt = DateTime.Now
});

// All we need to do now is to redirect the user back!
logger.LogDebug("Consent request successfully accepted, redirect to: {URL}", acceptRequest.RedirectTo);
return Redirect(acceptRequest.RedirectTo);
}

private bool CanSkipConsent(HydraOAuth2ConsentRequest challenge)
Expand Down

0 comments on commit 1babed1

Please sign in to comment.