I am using openiddict and trying to retrieve /userinfo, however, my userinfo controller never executes when debugging, but I do receive a response from the api.
response:
{
"sub": "1e56db90-fe77-47a6-b260-941a59bf32e4",
"iss": "https://localhost:7049/",
"aud": "postman"
}
program.cs
builder.Services.AddOpenIddict().AddCore(options =>
{
options.UseEntityFrameworkCore().UseDbContext<FaDbContext>();
})
.AddServer(options =>
{
options
.AllowClientCredentialsFlow()
.AllowAuthorizationCodeFlow()
.RequireProofKeyForCodeExchange()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
options.SetTokenEndpointUris("/token")
.SetAuthorizationEndpointUris("/connect/authorize")
.SetUserinfoEndpointUris("/connect/userinfo")
.SetVerificationEndpointUris("/connect/verify");
X509Certificate2 privateKey;
var bytes = File.ReadAllBytes(builder.Configuration["Auth:PrivateKeyPath"] ?? "");
privateKey = new X509Certificate2(bytes, "test");
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 encryptionKey;
var bytes2 = File.ReadAllBytes(builder.Configuration["Auth:EncryptionkeyPath"] ?? "");
encryptionKey = new X509Certificate2(bytes2, "test");
X509Store store2 = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
options
.AddSigningCertificate(privateKey)
.AddEncryptionCertificate(encryptionKey).DisableAccessTokenEncryption();
options.SetAccessTokenLifetime(TimeSpan.FromSeconds(60));
options.SetRefreshTokenLifetime(TimeSpan.FromDays(60));
options.RegisterScopes(Scopes.Email ,Scopes.Profile, Scopes.Roles, Scopes.OfflineAccess);
options
.UseAspNetCore()
.EnableTokenEndpointPassthrough()
.EnableAuthorizationEndpointPassthrough();
}
).AddValidation(options =>
{
options.AddAudiences("faid_client");
options.UseLocalServer();
options.UseAspNetCore();
});
UserInfoController.cs
public class UserInfoController : Controller
{
private readonly UserManager<User> _userManager;
public UserInfoController(UserManager<User> userManager)
=> _userManager = userManager;
[Microsoft.AspNetCore.Authorization.Authorize(AuthenticationSchemes = OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)]
[HttpGet("~/connect/userinfo"), HttpPost("~/connect/userinfo")]
[IgnoreAntiforgeryToken, Produces("application/json")]
public async Task<IActionResult> Userinfo()
{
var user = await _userManager.GetUserAsync(User);
if (user is null)
{
return Challenge(
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidToken,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
"The specified access token is bound to an account that no longer exists."
}));
}
var claims = new Dictionary<string, object>(StringComparer.Ordinal)
{
// Note: the "sub" claim is a mandatory claim and must be included in the JSON response.
[Claims.Subject] = await _userManager.GetUserIdAsync(user)
};
if (User.HasScope(Scopes.Email))
{
claims[Claims.Email] = await _userManager.GetEmailAsync(user);
claims[Claims.EmailVerified] = await _userManager.IsEmailConfirmedAsync(user);
}
if (User.HasScope(Scopes.Phone))
{
claims[Claims.PhoneNumber] = await _userManager.GetPhoneNumberAsync(user);
claims[Claims.PhoneNumberVerified] = await _userManager.IsPhoneNumberConfirmedAsync(user);
}
if (User.HasScope(Scopes.Roles))
{
claims[Claims.Role] = await _userManager.GetRolesAsync(user);
}
// Note: the complete list of standard claims supported by the OpenID Connect specification
// can be found here: http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
return Ok(claims);
}
}
You haven't enabled userinfo endpoint passthrough in your server setup so it's still using OpenIddict's default implementations.
Add
EnableUserinfoEndpointPassthrough()
like so:
options
.UseAspNetCore()
.EnableTokenEndpointPassthrough()
.EnableAuthorizationEndpointPassthrough()
.EnableUserinfoEndpointPassthrough();
And OpenIddict should pass the userinfo request to your controller action now.