Closed c-seeger closed 1 year ago
Can you try running the example of flutter_web_auth_2
and verify that your setup kind of resembles that one?
Yes I can reproduce the example when using pure flutter_web_auth_2
implementation against twitter. If I use the example it works, I think the main difference here is that the popup/new tab first opens twitter and then redirects back the window seems to loose its opener value.
I think its similar to this issue: window-opener-is-null-after-redirect
example code I use:
final String codeVerifier = _generateSecureAlphaNumeric(80);
final String codeChallenge = _generateCodeChallenge(codeVerifier);
final String state = _generateSecureAlphaNumeric(25);
final url = Uri.https('twitter.com', '/i/oauth2/authorize', {
'response_type': 'code',
'client_id': Environment().config.twitter.clientID,
'redirect_uri': Environment().config.twitter.redirectUri,
'scope': 'tweet.read',
'state': state,
'code_challenge': codeChallenge,
'code_challenge_method': 'S256',
});
final result = await FlutterWebAuth2.authenticate(
url: url.toString(),
callbackUrlScheme: Environment().config.twitter.customUriScheme,
contextArgs: ['twitter_oauth2_pkce::authenticateWindow']);
print(result);
utility functions
Map<String, String> _buildAuthorizationHeader({
required String clientId,
required String clientSecret,
}) {
final credentials = base64.encode(utf8.encode('$clientId:$clientSecret'));
return {'Authorization': 'Basic $credentials'};
}
String _generateSecureAlphaNumeric(final int length) {
final random = Random.secure();
final values = List<int>.generate(length, (i) => random.nextInt(255));
return base64UrlEncode(values);
}
String _generateCodeChallenge(String codeVerifier) {
final digest = sha256.convert(utf8.encode(codeVerifier));
final codeChallenge = base64UrlEncode(digest.bytes);
if (codeChallenge.endsWith('=')) {
//! Since code challenge must contain only chars in the range
//! ALPHA | DIGIT | "-" | "." | "_" | "~"
//! (see https://tools.ietf.org/html/rfc7636#section-4.2)
return codeChallenge.substring(0, codeChallenge.length - 1);
}
return codeChallenge;
}
the code works and i can authorize my app but once i reach the auth.html it errors
modified auth.html
<!DOCTYPE html>
<title>Authentication complete</title>
<p>Authentication is complete. If this does not happen automatically, please close the window.</p>
<script>
try{
window.opener.postMessage({
'flutter-web-auth-2': window.location.href
}, window.location.origin);
}catch(e) {
alert(e)
}
window.close();
</script>
Error:
TypeError: Cannot read properties of null (reading 'postMessage')
which refers to window.opener.postMessage
where window.opener
is null
from the stacktrace issue:
I just put another redirecting page in between. Now the popup goes first: To a page on my domain, second: To PayPal and Third: Back to my domain. This way it doesnt loose the parent information. Great
Maybe this could help since for now I open new tab with twitter, then twitter redirects back to auth.html
Just for reference, I was able to solve the issue a bit differently.
when pressing the button I fire and forget FlutterWebAuth2.authenticate
.
I'm currently using qlevar_router which allows me to do QR.params['code']
and QR.params['state']
to get current url parameters. Instead of auth.html
I just redirect back to the same page.
some notes here:
I need to use '_parent' as contextArgs and configure usePathUrlStrategy();
for this to work since twitter does not like redirect urls with #
However, this solution depends on an external package so if you can find a working solution with native support it would be great.
I am a bit confused about your contextArgs: ['twitter_oauth2_pkce::authenticateWindow']
.
I added that named parameter in order to be able to pass, e.g., popup
to the url launcher.
Are you sure that you need to pass that parameter there? See #40 for more info on why contextArgs
was added
no not really i just copied it form twitter-oauth2-pkce
, I guess it's not needed
Yeah tested it and it can be removed
I am having the same issue. I've seen some talk online on how this could be accomplished. some suggested putting the values into local storage and then periodically querying it for a time. Considering how each oauth implementation is slightly different it would make sense to not use window.opener as it may not always be opened from the same domain. Is this a solution that might be welcome in this package?
That also sounds like a good solution. If someone is willing to create a PR for this, I would gladly merge it after a short review. Alas, I am currently on vacation, so I cannot work on this myself
Ill take a crack at it on my personal account.
Hey it's me on my personal account. A couple of things:
I got it working with the local storage method 🎉
I noticed that windows and linux both have 90 second timeouts. I set the web timeout to be 5 mins (checking every second). Should the authenticate
method have a argument called timeout
that would adjust the default timeout value on web, windows, and linux? Or was that 90 second timeout there for another reason?
When it does timeout, what would be the best practice for throwing an error? Currently I have it doing the following:
PlatformException(
code: 'error',
message: 'Timeout waiting for callback value',
),);
But is there a better way to indicate that the call has timed out so it can be caught? (I'm new to contributing to dart packages so I may be unaware of a best practice)
I'm going to ignore the apple edge case for now. Not sure if this issue applies to apple and I have no way to test it currently.
Describe the bug
when trying to authenticate against twitter using twitter_oauth2_pkce which just uses flutter_web_auth_2 in the backend I managed to let it open the popup with correct redirect but when auth.html is called the window.opener.postMessage does not work since window.opener is null.
Expected behavior
window.opener should not be null or any other way to send the data back to it's parrent
Device (please complete the following information!)
flutter_web_auth_2
: ^2.0.4 (used by twitter-oauth2_pkce)