IdentityServer4 PKCE错误:“转换后的代码验证程序与代码挑战不匹配”

时间:2019-11-04 04:21:32

标签: identityserver4 pkce

我无法获得IdentityServer4 PKCE授权才能使用邮递员工作。

使用在线工具创建必要的部分:

选择一个随机字符串:

  

1234567890

获取其SHA-256哈希值:

  

c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646

Base64对哈希进行编码以获得代码挑战:

  

Yzc3NWU3Yjc1N2VkZTYzMGNkMGFhMTExM2JkMTAyNjYxYWIzODgyOWNhNTJhNjQyMmFiNzgyODYyZjI2ODY0Ng ==

在浏览器中,我导航至以下URL,填写凭据,然后从分散的重定向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

在兑换令牌代码时,我传递了code_verifier(SHA-256哈希),但是我的IdentityServer记录以下错误:

  

“转换后的代码验证程序与代码挑战不匹配”。

POST https://localhost:5000/connect/token
client_id=pkceclient
grant_type=authorization_code
code:-CesrmjPYjdLdDd5AviOZpR6GdjjkZia_ZapoJdGUZI
redirect_uri=https://jwt.ms
code_verifier=c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646

作者在他的blog post中使用以下代码生成这些部分。

var verifier = CryptoRandom.CreateRandomKeyString(64);
var challenge = verifier.ToCodeChallenge();

但是我无法在存储库中找到ToCodeChallenge方法的代码。

为什么我手动生成的挑战与验证过程中使用的挑战不匹配,我缺少什么?

3 个答案:

答案 0 :(得分:2)

在把这个问题放在一起时,我遇到了PKCE的specification文档,并发现以下内容:

  

code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

事实证明,我使用的在线工具未执行ASCII部分。

执行代码中的步骤,得到以下内容,当替换之前的值时,将在过程的第二步中通过验证。

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

答案 1 :(得分:1)

答案 2 :(得分:0)

此处对所选答案有所改进,不需要使用Sha256()扩展方法(credit)。

code_verifier随机生成器(用于/connect/token端点):

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生成器,基于code_verifier(对于/connect/authorize端点):

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;
    }
}

用法:

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);
}