Dart / Flutter中的Spotify PKCE:“ code_verifier错误”

时间:2020-09-12 18:11:55

标签: flutter dart oauth spotify pkce

使用带有Spotify-API的PKCE的授权代码流我得到了我的code_verifier不正确的错误,这是我目前所知道的编码问题。
{"error":"invalid_grant","error_description":"code_verifier was incorrect"}
这是我写的原始代码:

String getAuthUrl() {
    code = getRandomString(128);
    // saveToPrefs("verfifier_code", code);
    var hash = sha256.convert(ascii.encode(code));
    String code_challenge = base64Url.encode(hash.bytes);
    return Uri.parse(
            "https://accounts.spotify.com/authorize?response_type=code&client_id=${widget.client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Fauth&scope=user-top-read&code_challenge=$code_challenge&code_challenge_method=S256")
        .toString();
  }

这就是我对Spotify-Authorisation-Guide(https://developer.spotify.com/documentation/general/guides/authorization-guide/)的理解。

找到此帖子(https://stackoverflow.com/a/63174909/14266484)之后,我尝试将修补程序移植到Dart,但失败了。据我了解,代码对ascii编码的code_verifier进行哈希处理,然后使用btoa()再次将其转换为ascii。此功能似乎也可以执行base64(但不能执行base64Url,也许这就是为什么某些零件必须手动更换的原因?)。

String getAuthUrl() {
    // also tried static verifier_codes for debugging, so the getRandomString() function is working properly
    code = getRandomString(128);
    // saveToPrefs("verfifier_code", code);
    var hash = sha256.convert(ascii.encode(code));
    // this does not work with either base64 or base64Url
    String code_challenge = base64.encode(hash.bytes).replaceAll(RegExp(r"/\+/g"), '-').replaceAll(RegExp(r"/\//g"), '_').replaceAll(RegExp(r"/=+$/"), '');
    return Uri.parse(
            "https://accounts.spotify.com/authorize?response_type=code&client_id=${widget.client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Fauth&scope=user-top-read&code_challenge=$code_challenge&code_challenge_method=S256")
        .toString();
  }

我还尝试了不同的编码方式:
-使用String.codeUnits(但这使用的是UTF-16)
-使用String.fromCharCodes()(应使用ASCII?)获取sha256函数的字符串以及base64(-Url)函数的字符串(应使用ASCII?)
-在ASCII和UTF-8之间切换(在这种情况下,这不应该有所作为,因为我的verifier_code仅由ASCII字符组成)

编辑:
要发出我使用的请求:

var res = await http.post(endpoint, body: {"client_id":widget.client_id, "grant_type":"authorization_code", "code":value, "redirect_uri":"http://localhost/auth", "code_verifier":code});

1 个答案:

答案 0 :(得分:0)

经过更多研究,我发现正在发生的重要事情是必须删除挑战末尾的“ =”(base64Url不能这样做吗?)。无论如何,这就是工作代码:

编辑代码:

String getAuthUrl() {
    code = getRandomString(128);
    var hash = sha256.convert(ascii.encode(code));
    String code_challenge = base64Url.encode(hash.bytes).replaceAll("=", "").replaceAll("+", "-").replaceAll("/", "_");
    return Uri.parse(
            "https://accounts.spotify.com/authorize?response_type=code&client_id=${widget.client_id}&redirect_uri=http%3A%2F%2Flocalhost%2Fauth&scope=user-top-read&code_challenge=$code_challenge&code_challenge_method=S256")
        .toString();
  }


编辑:
进一步的“ +”必须替换为“-”,“ /”替换为“ _”!