问题
I cannot get IdentityServer4 PKCE authorization to work using Postman.
Using online tools I create the necessary parts:
Choose a random string:
1234567890
Get its SHA-256 hash:
c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646
Base64 encode the hash to get the code challenge:
Yzc3NWU3Yjc1N2VkZTYzMGNkMGFhMTExM2JkMTAyNjYxYWIzODgyOWNhNTJhNjQyMmFiNzgyODYyZjI2ODY0Ng==
In the browser I navigate to the following URL, fill in my credentials and retrieve the code from the fragmented redirect URL.
GET https://localhost:5000/connect/authorize
?client_id=pkceclient
&scope=openid
&response_type=code
&redirect_uri=https://jwt.ms
&state=abc
&nonce=xyz
&code_challenge=Yzc3NWU3Yjc1N2VkZTYzMGNkMGFhMTExM2JkMTAyNjYxYWIzODgyOWNhNTJhNjQyMmFiNzgyODYyZjI2ODY0Ng==
&code_challenge_method=S256
When redeeming the code for a token I pass the code_verifier (SHA-256 hash) but my IdentityServer logs the following error:
"Transformed code verifier does not match code challenge".
POST https://localhost:5000/connect/token
client_id=pkceclient
grant_type=authorization_code
code:-CesrmjPYjdLdDd5AviOZpR6GdjjkZia_ZapoJdGUZI
redirect_uri=https://jwt.ms
code_verifier=c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646
In his blog post, the author uses the following code to generate the parts.
var verifier = CryptoRandom.CreateRandomKeyString(64);
var challenge = verifier.ToCodeChallenge();
but I cannot find the code in the repositories for the ToCodeChallenge
method.
Why doesn't my manually generated challenge match the one used in the verification process, what am I missing?
回答1:
While putting this question together I came across the specification document for PKCE and found the following line:
code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
It turns out the ASCII part is not carried out by the online tools that I used.
Implementing the steps in code I get the following which, when substituting the values from before, passes the verification in the second step of the process.
var codeVerifier = "c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646";
var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier);
var hashedBytes = codeVerifierBytes.Sha256();
var transformedCodeVerifier = Base64Url.Encode(hashedBytes);
code_challenge: 51FaJvQFsiNdiFWIq2EMWUKeAqD47dqU_cHzJpfHl-Q
code_verifier: c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646
回答2:
Following links helps to achieve the PKCE-AuthZ-Code flow.
https://auth0.com/docs/api-auth/tutorials/authorization-code-grant-pkce
https://github.com/gilbert-fernandes/S256Code/blob/master/src/S256Code.java
回答3:
Here is a slight improvement for the selected answer, without the need for the Sha256()
extension method (credit).
code_verifier
random generator (for the /connect/token
endpoint):
private string GenerateCodeVerifier()
{
var rng = RandomNumberGenerator.Create();
var bytes = new byte[32];
rng.GetBytes(bytes);
// It is recommended to use a URL-safe string as code_verifier.
// See section 4 of RFC 7636 for more details.
var code_verifier = Convert.ToBase64String(bytes)
.TrimEnd('=')
.Replace('+', '-')
.Replace('/', '_');
return code_verifier;
}
code_challenge
generator based on a code_verifier
(for the /connect/authorize
endpoint):
private string GenerateCodeChallenge(string code_verifier)
{
var code_challenge = string.Empty;
using (var sha256 = SHA256.Create())
{
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(code_verifier));
code_challenge = Convert.ToBase64String(challengeBytes)
.TrimEnd('=')
.Replace('+', '-')
.Replace('/', '_');
return code_challenge;
}
}
Usage:
using System;
using System.Security.Cryptography;
using System.Text;
[TestMethod]
public void CodesTest()
{
string code_verifier = GenerateCodeVerifier();
Console.WriteLine("code_verifier:");
Console.WriteLine(code_verifier);
string code_challenge = GenerateCodeChallenge(code_verifier);
Console.WriteLine("code_challenge:");
Console.WriteLine(code_challenge);
}
来源:https://stackoverflow.com/questions/58687154/identityserver4-pkce-error-transformed-code-verifier-does-not-match-code-chall