Spotify PKCE in Dart/Flutter: "code_verifier was incorrect" - flutter

Using the Authorization Code Flow with PKCE of the Spotify-API I am getting the error that my code_verifier is incorrect, which has to be an encoding problem from what I know by now.
{"error":"invalid_grant","error_description":"code_verifier was incorrect"}
This is the original code I wrote:
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();
}
This is how I understand the Spotify-Authorisation-Guide (https://developer.spotify.com/documentation/general/guides/authorization-guide/).
After finding this post (https://stackoverflow.com/a/63174909/14266484) I tried porting the fix to Dart but failed. As far as I understand it the code hashes the in ascii encoded code_verifier and then uses btoa() to convert it into ascii again. This function also seems to do base64 (but not base64Url, maybe this is why certain parts have to be replaced manually?).
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();
}
I also tried different ways of encoding:
-Using String.codeUnits (But this is using UTF-16)
-Getting a String for the sha256-function aswell the base64(-Url)-function with String.fromCharCodes() (which should be using ASCII?)
-Switching between ASCII and UTF-8 (Which should not make a difference in that case as my verifier_code is made up of ASCII-Characters only)
EDIT:
To make the requests I use:
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});

After some more research I found out that the important thing that is happening is that the "=" at the end of the challenge has to be removed (Shouldn't base64Url do that?). Anyways, that is the working code:
EDITED CODE:
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();
}
EDIT:
Further "+" has to be replaced with "-" and "/" with "_"!

Related

Decode utc8 character from string Flutter

I'm unable to decode the utc8 characters from string.
Below line getting from API
replace the cable if a fault is found â for example
actual string
replace the cable if a fault is found - for example
Can any one help me how to fix this ?
Thanks!!!
You can use the Charset Detector Flutter Charset Detector Package to convert it to the correct encoding.
I already used it, and it works perfectly. You just have to convert the body of the response to the desired encoding.
You pass the bodyBytes field to the package autoDecode method.
Uint8List bodyBytes = response.bodyBytes;
DecodingResult decoded = (await CharsetDetector.autoDecode(bodyBytes));
String charset = decoded.charset;
String bodyInRightEncodage = decoded.string;
The response field is a http response object.
Below line is working fine
jsonDecode(utf8.decode(response.bodyBytes, allowMalformed: true));

How to display Unicode Smiley from json response dynamically in flutter

How to display Unicode Smiley from json response dynamically in flutter. It's display properly when i declare string as a static but from dynamic response it's not display smiley properly.
Static Declaration: (Working)
child: Text("\ud83d\ude0e\ud83d\ude0eThis is just test notification..\ud83d\ude0e\ud83d\ude0e\ud83d\udcaf\ud83d\ude4c")
Dynamic Response:
"message":"\\ud83d\\ude4c Be Safe at your home \\ud83c\\udfe0",
When i'm parse and pass this response to Text then it's consider Unicode as a String and display as a string instead of Smiley Code is below to display text with smiley:
child: Text(_listData[index].message.toString().replaceAll("\\\\", "\\"))
Already go through this: Question but it's only working when single unicode not working with multiple unicode.
Anyone worked with text along with unicode caracter display dynamically then please let me know.
Another alternate Good Solution I would give to unescape characters is this:
1st ->
String s = "\\ud83d\\ude0e Be Safe at your home \\ud83c\\ude0e";
String q = s.replaceAll("\\\\", "\\");
This would print and wont be able to escape characters:
\ud83d\ud83d Be Safe at your home \ud83c\ud83d
and above would be the output.
So what one can do is either unescape them while parsing or use:
String convertStringToUnicode(String content) {
String regex = "\\u";
int offset = content.indexOf(regex) + regex.length;
while(offset > 1){
int limit = offset + 4;
String str = content.substring(offset, limit);
// print(str);
if(str!=null && str.isNotEmpty){
String uni = String.fromCharCode(int.parse(str,radix:16));
content = content.replaceFirst(regex+str,uni);
// print(content);
}
offset = content.indexOf(regex) + regex.length;
// print(offset);
}
return content;
}
This will replace and convert all the literals into unicode characters and result and output of emoji:
String k = convertStringToUnicode(q);
print(k);
😎 Be Safe at your home 🈎
That is above would be the output.
Note: above answer given would just work as good but this is just when you want to have an unescape function and don't need to use third-party libraries.
You can extend this using switch cases with multiple unescape solutions.
Issue resolved by using below code snippet.
Client client = Client();
final response = await client.get(Uri.parse('YOUR_API_URL'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
final extractedData = json.decode(response.body.replaceAll("\\\\", "\\"));
}
Here we need to replace double backslash to single backslash and then decode JSON respone before set into Text like this we can display multiple unicode like this:
final extractedData = json.decode(response.body.replaceAll("\\",
"\"));
Hope this answer help to other

Flutter - Character encoding is not behaving as expected

I am parsing a local JSON file that has words containing rarely used special characters in Icelandic.
When displaying the characters I get mixed up symbols but not the characters, for some others I just get a square instead of a symbol.
I am using this type of encoding "\u00c3"
Update: Example of the characters I am using: þ, æ, ý, ð
Q: What is the best way to display those kind of characters and avoid any chance of display failures?
Update #2:
How I am parsing:
Future<Null> getAll() async{
var response = await
DefaultAssetBundle.of(context).loadString('assets/json/dictionary.json');
var decodedData = json.decode(response);
setState(() {
for(Map word in decodedData){
mWordsList.add(Words.fromJson(word));
}
});
}
The class:
class Words{
final int id;
final String wordEn, wordIsl;
Words({this.id, this.wordEn, this.wordIsl});
factory Words.fromJson(Map<String, dynamic> json){
return new Words(
id: json['wordId'],
wordEn: json['englishWord'],
wordIsl: json['icelandicWord']
);
}
}
JSON Model:
{
"wordId": 47,
"englishWord": "Age",
//Here's a String that has two special characters
"icelandicWord": "\u00c3\u00a6vi"
}
I had similar issues with accented characters. They were not displayed as expected.
This worked for me
final codeUnits = source.codeUnits;
return Utf8Decoder().convert(codeUnits);
The problem is that your JSON is stored locally.
Let's say you have
Map<String, String> jsonObject = {"info": "Æ æ æ Ö ö ö"};
So to show your text correctly you have to encode and decode back your JSON with utf-8.
I understand that's serialization and deserialization are costly operations, but's it's a workaround for locally stored JSON objects that contains UTF-8 texts.
import 'dart:convert';
jsonDecode(jsonEncode(jsonObject))["info"]
If you get that JSON from server, then it's much more simpler, for example in dio package you can chose contentType params that's is "application/json; charset=utf-8" by default.

crypto-js decrypt from Hex

I am trying to make a JavaScript function with package crypto-js to decode AES (CBC mode).
I input the data in an online decoding tool and it decrypted correctly, so I am sure the following data is correct, but I just can't reproduce it by JavaScript.
Here is the online decrypting (so I'm sure the data, key, iv are correct): http://aes.online-domain-tools.com/link/deb718giF4dUxZylq/
My code with crypto-js#3.1.8:
// data, key, iv are all Hex
var data = "bd6e0a73147a2c224c7c20346d0e9a138b744a5d94463cdff6dbb965055f974f097104399d2c40af2f0ac667f3857e70e9703bf27f6411f7e97c3449e8921f3c98e665914689b4b77b5bbcc8d8bc319e680eb89eedb1c25178923ae57fb3fb476755d6009f1aed88fffcb9b2ed3b4cf6f23d9c4c56da1dde6619e45a8d6f06412853ae1941cf554b6824112a913750a7485ed67fb38b950411310410de998f2597c2fcc81a305b0df369f54b75426176";
var key = 'befce5c6da98837ea421811c832817ae';
var iv = "a884a7edd5d06a48d6da9ad11fd36a75";
// transfer Hex to WordArray
var _data = CryptoJS.enc.Hex.parse(data);
var base64_data = _data.toString(CryptoJS.enc.Base64);
var _key = CryptoJS.enc.Hex.parse(key);
var _iv = CryptoJS.enc.Hex.parse(iv);
decrypted = CryptoJS.AES.decrypt(
base64_data, // pass base64
_key, // pass WordArray
{iv: _iv, // pass WordArray
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
})
console.log(decrypted.toString(CryptoJS.enc.Utf8));
// out put fail to match Utf8
It output Error: Malformed UTF-8 data
The decoded string should be: (the link is not important)
https://emogo-media-testing.s3.amazonaws.com/1503342403787_blob?AWSAccessKeyId=AKIAI5MUDCK6XYWKGAKA&Expires=1534882403&Signature=t1PFesQuOpOlIMKoOqje%2Bs7I%2Fhg
Any hint is appreciated. Thank you!
I know it has been a while since you asked the question but I will respond just so the next person does not stumble upon an unanswered question.
Your code works fine, it decrypts AES.CBC encrypted data correct, the problem lies with your input data.
Your encrypted data string should have looked like:
80b7c4881334675693ef9c95259e70b24d0736e98f8424233d5e37f353261c2a589287bc3f675449f7d8ed4e2289a4c06b22d7f83efc09cfb72abe3a76e193a8efbdc968232d29b9b58135bfa24d51e60e34791f652a0aa806d0be7734dd61a930a30c99f31f08740cdb182af07b19d5b4274deb958d984b3ccb9d6e2be0cfa3a026dd6b734dbf1dd3635bc7bcceface9c55dfb9455ca834a6dbd1aa0f3c23923ce6aeba59acbc80d681fee73487b9004496540830d44102b94e35eac291c4e3b8c9ac168ae799e46cde45ee652415ae69992d0f7527045fd42b82e9e6946cfb2dbcc3b93f19ff0e5035ab12250f7a917975b2f7c069cbd8a0ba0d94b318634a
for this example to work correctly.
The key you used is not a hex string but a text string. Your online example is no longer valid but I figured it out after a couple of tries.
If change the following line:
var _key = CryptoJS.enc.Hex.parse(key);
to:
var _key = CryptoJS.enc.Utf8.parse(key);
Your code example will work fine with your original data string.
When you decrypted the text on http://aes.online-domain-tools.com/ you probably had the plaintext textbox selected instead of hex for your key input.

KRL: Signing requests with HMAC_SHA1

I made a test suite for math:hmac_* KRL functions. I compare the KRL results with Python results. KRL gives me different results.
code: https://gist.github.com/980788 results: http://ktest.heroku.com/a421x68
How can I get valid signatures from KRL? I'm assuming that they Python results are correct.
UPDATE: It works fine unless you want newline characters in the message. How do I sign a string that includes newline characters?
I suspect that your python SHA library returns a different encoding than is expected by the b64encode library. My library does both the SHA and base64 in one call so I to do some extra work to check the results.
As you show in your KRL, the correct syntax is:
math:hmac_sha1_base64(raw_string,key);
math:hmac_sha256_base64(raw_string,key);
These use the same libraries that I use for the Amazon module which is testing fine right now.
To test those routines specifically, I used the test vectors from the RFC (sha1, sha256). We don't support Hexadecimal natively, so I wasn't able to use all of the test vectors, but I was able to use a simple one:
HMAC SHA1
test_case = 2
key = "Jefe"
key_len = 4
data = "what do ya want for nothing?"
data_len = 28
digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79
HMAC SHA256
Key = 4a656665 ("Jefe")
Data = 7768617420646f2079612077616e7420666f72206e6f7468696e673f ("what do ya want for nothing?")
HMAC-SHA-256 = 5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
Here is my code:
global {
raw_string = "what do ya want for nothing?";
mkey = "Jefe";
}
rule first_rule {
select when pageview ".*" setting ()
pre {
hmac_sha1 = math:hmac_sha1_hex(raw_string,mkey);
hmac_sha1_64 = math:hmac_sha1_base64(raw_string,mkey);
bhs256c = math:hmac_sha256_hex(raw_string,mkey);
bhs256c64 = math:hmac_sha256_base64(raw_string,mkey);
}
{
notify("HMAC sha1", "#{hmac_sha1}") with sticky = true;
notify("hmac sha1 base 64", "#{hmac_sha1_64}") with sticky = true;
notify("hmac sha256", "#{bhs256c}") with sticky = true;
notify("hmac sha256 base 64", "#{bhs256c64}") with sticky = true;
}
}
var hmac_sha1 = 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79';
var hmac_sha1_64 = '7/zfauXrL6LSdBbV8YTfnCWafHk';
var bhs256c = '5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843';
var bhs256c64 = 'W9zBRr9gdU5qBCQmCJV1x1oAPwidJzmDnexYuWTsOEM';
The HEX results for SHA1 and SHA256 match the test vectors of the simple case.
I tested the base64 results by decoding the HEX results and putting them through the base64 encoder here
My results were:
7/zfauXrL6LSdBbV8YTfnCWafHk=
W9zBRr9gdU5qBCQmCJV1x1oAPwidJzmDnexYuWTsOEM=
Which match my calculations for HMAC SHA1 base64 and HMAC SHA256 base64 respectively.
If you are still having problems, could you provide me the base64 and SHA results from python separately so I can identify the disconnect?