Reputation: 180
I'm trying to implement the authorization code flow with PKCE using OpenIdDict
The basic flow is as follows:
Expected behavior: Output AccessToken
Actual behavior: It tried to redirect to the redirect url
Here is my start-up code
.AddCookie(AuthConstants.ConsumerAppBiometricAuthenticationScheme, config =>
{
config.Cookie.HttpOnly = true;
//options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
config.Cookie.SameSite = SameSiteMode.Lax;
config.Cookie.Name = AuthConstants.ConsumerAppBiometricAuthenticationScheme;
config.LoginPath = new PathString("/api/BiometricAuthentication/BiometricChallenge");
config.ExpireTimeSpan = TimeSpan.FromMinutes(Clients.DefaultAccessTokenLifeTime);
config.SlidingExpiration = true;
})
Here is my code inside authorization endpoint
var authScheme = AuthConstants.ConsumerAppBiometricAuthenticationScheme;
var result = await HttpContext.AuthenticateAsync(authScheme);
if (!result.Succeeded)
return Challenge(authScheme!);
var phone = result.Principal.Claims.FirstOrDefault(x => x.Type == ClaimTypes.MobilePhone);
var claimsPrincipal = await _authorizationService.GrantAuthorizationCode(new AuthorizationCodeCommand
{
ClientId = request.ClientId,
Scopes = ImmutableArray<string>.Empty,
UserName = phone.Value,
Audiences = request.Audiences
});
// Signing in with the OpenIddict authentication scheme trigger OpenIddict to issue a code (which can be exchanged for an access token)
return SignIn(claimsPrincipal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
Here is my code inside the Authentication
[HttpGet]
public async Task<BiometricChallengeView> BiometricChallenge(string returnUrl)
{
var query = Helper.GetQueryParams(HttpContext.Request.Host.ToString(), returnUrl);
var phoneNumber = query.Get(AuthConstants.PhoneNumber);
var challenge = await _authenticationService.GetChallenge(phoneNumber);
return new BiometricChallengeView
{
ReturnUrl = returnUrl,
UserName = phoneNumber,
Challenge = challenge
};
}
[HttpPost]
public async Task<IActionResult> BiometricChallenge(BiometricChallengeView encryptedChallenge)
{
await _authenticationService.VerifyChallenge(encryptedChallenge.UserName, encryptedChallenge.Challenge);
await SignInAsync(encryptedChallenge.UserName);
return Redirect(encryptedChallenge.ReturnUrl);
}
private async Task SignInAsync(string phone)
{
const string scheme = AuthConstants.ConsumerAppBiometricAuthenticationScheme;
var claims = new List<Claim>
{
new(ClaimTypes.MobilePhone, phone),
new(ClaimTypes.PrimarySid, Guid.NewGuid().ToString())
};
var claimsIdentity = new ClaimsIdentity(claims, scheme);
await HttpContext.SignInAsync(scheme, new ClaimsPrincipal(claimsIdentity));
}
Upvotes: 0
Views: 258
Reputation: 42000
It's the expected behavior: the code flow is a two-step process that first consists in redirecting the user agent back to the client application with an intermediate token called "authorization code": the access token is only delivered during a second step, via a backchannel API request called "token request".
Upvotes: 0