aws-amplify / amplify-flutter

A declarative library with an easy-to-use interface for building Flutter applications on AWS.
https://docs.amplify.aws
Apache License 2.0
1.31k stars 242 forks source link

Document how to get encoded access token #5023

Open Glydric opened 3 months ago

Glydric commented 3 months ago

Description

I was developing an application in dart when I found out that the jwt value i was getting printing directly let ses = await Amplify.Auth.fetchAuthSession() safePrint(ses); is different that the one obtained using final tokens = ses.toJson()["userPoolTokens"] as CognitoUserPoolTokens; safePrint(tokens.accessToken.encode().toString()); that should be used to extract the user pool token.

I found out that the signature is equal, but using the second method it was someway reformatting the token and obtain a different base 64 value. that is instead wrong Indeed the first can be verified with jwt.io, while the latter is impossible to verify. This is a real problem as I seen from previous issues that I'm not the only one that founds out this problem. but maybe I just discovered this difference. I just discovered this on an iPhone 15 with ios 17.5, build using flutter 3.19.5 and dart 3.3.3 on macos 14.5

Categories

Steps to Reproduce

let ses = await Amplify.Auth.fetchAuthSession() safePrint(ses); // Correct accessToken jwt final tokens = ses.toJson()["userPoolTokens"] as CognitoUserPoolTokens; safePrint(tokens.accessToken.encode().toString()); // Wrong accessToken jwt

Screenshots

No response

Platforms

Flutter Version

3.19.5

Amplify Flutter Version

2.1.0

Deployment Method

Custom Pipeline

Schema

No response

Glydric commented 3 months ago

Correcting myself the problem is not about the two methods but is about using encode function, just don't use it and instead use toJson(), so use the following implementation

final cognitoPlugin = Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);
final result = await cognitoPlugin.fetchAuthSession();
final token = result.userPoolTokensResult.value.accessToken.toJson();

the token then can be used to sign any request (I can now verify in the backend)

Jordan-Nelson commented 3 months ago

Hi @Glydric I think the difference you are noticing is due to the difference between the .json(), .encode(), and .toString() methods on JsonWebToken. You can see those three functions below.

https://github.com/aws-amplify/amplify-flutter/blob/3fe76c0e90454a8406d98e0288d03ae651b3f8bd/packages/auth/amplify_auth_cognito_dart/lib/src/jwt/src/token.dart#L85-L98

Note that toJson calls .raw which in turn calls .encode() https://github.com/aws-amplify/amplify-flutter/blob/3fe76c0e90454a8406d98e0288d03ae651b3f8bd/packages/auth/amplify_auth_cognito_dart/lib/src/jwt/src/token.dart#L65-L66

In the first example (let ses = await Amplify.Auth.fetchAuthSession() safePrint(ses);) .toString() will be used where in the other examples .json() or .encode() is used.

It sounds like you may have already found a solution to the issue you were facing, but let me know if that is not the case.

Glydric commented 3 months ago

Hi @Jordan-Nelson, yes, I already found a solution, but I think that this can be a bit confusing for any new developer here and like me will lost a lot of time trying to get the correct JWT. Also I didn't read anything about this important difference on the amplify website, so I created this issue not only to find a final solution but also to help others.

Jordan-Nelson commented 3 months ago

There are API docs for .raw and .encode(). .toString() is only overridden for debugging purposes. It really is not intended to be used in other contexts.

Were you expecting .toString() to return the encoded token?

Jordan-Nelson commented 3 months ago

We have labeled this as a docs issue. We will look to add some info to the main docs site to make this more clear.