Describe the bug
A clear and concise description of what the bug is.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Should return the token from Cognito
Screenshots
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
Sample code
https://aws-amplify.github.io/docs/js/authentication
You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app.
The bug is caused by this line: https://github.com/aws-amplify/amplify-js/blob/db55ff3dff31c64a246180f39eb0a04a89fd16e1/packages/auth/src/OAuth/OAuth.ts#L144
When I commented the code to be like these:
body: typeof URLSearchParams !== 'undefined' ? new URLSearchParams(body) : body
It works! When I tried using POSTman with the raw parameter also success
@irwansyahwii can make it clearer that what's your work around to make it work? Also can you provide the version of react native you are using?
@powerful23 so I am trying to use Amplify's Facebook login. I am using the withOAuth HOC in RN. I am using RN version 0.59.6. When I click the button and call the facebookSignIn() method from the HOC, it was failed. When I traced and debug it turns out the problem was in the last step of the OAuth flow. When Amplify tried to get the token from https://domain.amazoncognito.com/oauth2/token it was failed and get "invalid request" error. So post the request manually using POSTman and using the raw post data without wrapping it with the URLSearchParams() and it was succeed. So then I commented the code on OAuth.ts line 144 and replaced it with the one that is using the raw values and it works.
Is it clear?
Hi @irwansyahwii
Looks like there were some changes made to react native 0.59.x (see facebook/react-native#23922)
Can you try the workarounds mentioned there?
These ones specifically caught my attention:
import { polyfillGlobal } from 'react-native/Libraries/Utilities/PolyfillFunctions';
polyfillGlobal('URLSearchParams', () => require('url-search-params'));
or
import 'node-libs-react-native/globals';
import { polyfillGlobal } from 'react-native/Libraries/Utilities/PolyfillFunctions';
polyfillGlobal('URLSearchParams', () => require('whatwg-url').URLSearchParams);
Hello,
Any update on this? The workarounds don't work for me.
In my case Safari opens when I call "withOAuth.loginFacebook", but after authenticating with Facebook and my deep link opens, I get "Open in MyApp?" and my app activates, then I get the following error:
YellowBox.js:67 Possible Unhandled Promise Rejection (id: 0):
TypeError: Parameter 'url' must be a string, not object
TypeError: Parameter 'url' must be a string, not object
Appears to be coming from "Auth._handleAuthResponse" at the line:
currentUrl = URL || (core.browserOrNode().isBrowser ? window.location.href : null);
None of the Hub events fire and OAuth flow breaks, no user created in User Pool etc.
@manueliglesias sorry for late response. But I haven't tried your work around since I had applied my own by monkey patching the OAuth instance using these codes:
export class AmplifyOAuthBugInitializer implements ISystemInitialier{
constructor(protected decoratee:ISystemInitialier){
}
initialize(): void {
this.decoratee.initialize();
fileLogger().debug("Overriding OAuth._handleCodeFlow to remove the bug");
(OAuth.prototype as any)._handleCodeFlow = async function (currentUrl:any) {
fileLogger().debug("OAuth's _handleCodeFlow() called using our own version");
/* Convert URL into an object with parameters as keys
{ redirect_uri: 'http://localhost:3000/', response_type: 'code', ...} */
const { code } = (parse(currentUrl).query || '')
.split('&')
.map((pairings:any) => pairings.split('='))
.reduce((accum:any, [k, v]:[any, any]) => ({ ...accum, [k]: v }), { code: undefined });
if (!code) { return; }
const oAuthTokenEndpoint = 'https://' + this._config.domain + '/oauth2/token';
dispatchAuthEvent(
'codeFlow',
{},
`Retrieving tokens from ${oAuthTokenEndpoint}`
);
const client_id = isCognitoHostedOpts(this._config)
? this._cognitoClientId
: this._config.clientID;
const redirect_uri = isCognitoHostedOpts(this._config)
? this._config.redirectSignIn
: this._config.redirectUri;
const code_verifier = oAuthStorage.getPKCE();
const oAuthTokenBody = {
grant_type: 'authorization_code',
code,
client_id,
redirect_uri,
...(code_verifier ? { code_verifier } : {})
};
logger.debug(`Calling token endpoint: ${oAuthTokenEndpoint} with`, oAuthTokenBody);
const body = Object.entries(oAuthTokenBody)
.map(([k, v]) =>`${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
const { access_token, refresh_token, id_token, error } = await (await fetch(oAuthTokenEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body
}) as any).json();
if (error) {
throw new Error(error);
}
return {
accessToken: access_token,
refreshToken: refresh_token,
idToken: id_token
};
};
}
}
import { polyfillGlobal } from 'react-native/Libraries/Utilities/PolyfillFunctions'; polyfillGlobal('URLSearchParams', () => require('url-search-params'));
It helps with URLSearchParams, but I still have an error, cause fetch method doesn't get value for body from toString() and I don't understand why(
And my request for oauth2/token become with next body:
{
__URLSearchParams__:0.2509882737289457
}
Can you fix it, cause it doesn't work with fresh react-native. And I couldn't find any way how to handle it without changes in library code(
"aws-amplify": "1.1.28",
"aws-amplify-react-native": "2.1.12",
"react-native": "0.59.8",
I was able to get logging in via withOAuth to work by not only polyfilling URLSearchParams, but also by deleting the global reference as mentioned here. However, that leads to other subsequent errors (example here).
Is it reasonable to consider using a different implementation of URLSearchParams instead of relying on the global once, since RN has hijacked it with a half-baked implementation?
I think deleting it is going to cause more problems on > RN 59 if they've added it for a reason.
I've attempted to polyfill / replace URLSearchParams with whatwg-url's implementation as per this comment from @manueliglesias (and various other ways) and the end result is that the polyfill/replacement works, but the amplify fetch call here ends up sending no body at all.
It looks like it's going to be simpler to monkey patch amplify to replace the ternary operator for the body attribute and just send the body const which is already set correctly, as per this comment did.
Most helpful comment
I was able to get logging in via withOAuth to work by not only polyfilling URLSearchParams, but also by deleting the global reference as mentioned here. However, that leads to other subsequent errors (example here).
Is it reasonable to consider using a different implementation of URLSearchParams instead of relying on the global once, since RN has hijacked it with a half-baked implementation?