Hey all,
So I have a pretty standard WebBrowser based OAuth flow for using Instagram login with my app. It’s been working just fine until I upgraded to SDK 27 with the new Linking changes, and I’m having issues adapting the new API.
It’s pretty standard:
- Call Instagram API with a redirect URI to my own backend, and a
state
param containing the app redirect URL - In my backend, read out the
state
var and redirect back to the app with the one-time-use code from IG - In app, call the backend with this code to exchange for an access token.
Note that step 2 is performed by Expo’s server if using AuthSession, but I like the control, and it’s been working just fine until now.
The code is also pretty standard, but here it is:
const appDeepLinkPath = 'auth/instagram/v2/'
const appRedirectUri = Constants.linkingUri + appDeepLinkPath
....
openWebBrowserAsync = async () => {
this.addLinkingListener();
const clientID = getConfig().instagram.clientId;
const query = `client_id=${clientID}&redirect_uri=${proxyRedirectUri}&response_type=code&state=${appRedirectUri}`;
const stringURL = `https://api.instagram.com/oauth/authorize/?${query}`;
const encodedURL = encodeURI(stringURL);
const result = await WebBrowser.openBrowserAsync(encodedURL);
if (result.type === 'cancelled' || result.type === 'dismissed') {
console.log(TAG, 'Browser dismissed, no result - cancelled');
}
this.removeLinkingListener();
};
addLinkingListener = () => {
Linking.addEventListener('url', this.handleRedirect);
};
removeLinkingListener = () => {
Linking.removeEventListener('url', this.handleRedirect);
};
handleRedirect = event => {
WebBrowser.dismissBrowser();
const codeIndex = event.url.indexOf('code');
const code = event.url.substr(codeIndex + 5); // 4 chars in 'code' + 1 for '='. Doing it with substr instead of .parse util func to try to accomodate the new linking patterns
if (code && code.length > 1) {
this.props.actions.getJwtWithCode(code);
} else {
console.log(TAG, `No code in data. ${JSON.stringify(event)}\n`);
captureException(new Error(`No code returned ${JSON.stringify(event)}`));
this.props.setErrorRetrivingToken();
}
};
The above produces some weird results that varies betweens platforms. Note that I use a release channel, test-v2
, in the following.
On iOS
The above works on a published Expo build, but in a local dev env (LAN setup, same WiFi), I get a screen a la this:
with the URL being
exp://192.168.0.27:19000/auth/instagram/v2/?code=12345
On Android
On the published Expo build, I’m getting a screen saying “No experience found” with the following URL (decoded here):
exp://exp.host/@[USER]/[PROJECT]?release-channel=test-v2auth/instagram/v2//code=12232131
Notice here
- No slash between release channel and app path, double / before the code
On the local dev build, my backend is returning ‘url not allowed’ because it’s receving the following params:
redirect?code=SOMECODE&state=exp://192.168.0.27:19000auth/instagram/v2/
Notice again the missing / between port and the app path, confusing my backends whitelisting patterns.
Observations so far:
- There is a difference between how iOS and Android resolves
Constants.linkingUri
:
On Android:
exp:192.168.0.27:19000
On iOS (notice the trailing slash)
exp:192.168.0.27:19000/
- There is a difference between how the platforms handle release channel param
Android inserts the release channel param between the slug name and the app path, i.e.
exp://exp.host/@[USER]/[PROJECT]?release-channel=test-v2[APP PATH][OTHER PARAMS]
where iOS skips the release channel in the URI altogether, i.e.
exp://exp.host/@[USER]/[PROJECT][APP PATH][OTHER PARAMS]
- If I show the result of
appRedirectUri
in a<Text />
, it also shows up differently
On iOS:
exp://exp.host/@[USER]/[PROJECT]/–/[APP PATH]
On Android:
exp://exp.host/@[USER]/[PROJECT]/–/?release-channel=test-v2[APP PATH]
- Where did
/--/
enter the picture? Is it the ‘new’+
sign for deep linking in Expo?
So far, so… good? Let me try prepending a slash before the deep link URI to alleviate some of the issues:
On iOS
Still works on published project, yay! It now looks like this:
exp://exp.host/@[USER]/[PROJECT]/--//auth/instagram/v2/
Still does not work on local build, though. Getting the ‘There was a problem loading the requested app’ screen again, this time with the URL
exp://192.168.0.27:19000//auth/instagram/v2/?code=[THE CODE]
On Android
On local build, getting a blue screen saying “Something went wrong. Could not load”
exp://192.168.0.27:19000/auth/instagram/v2
On published build, getting blue 'Something went wrong. No experience found at"
exp://exp.host/@[USER]/[PROJECT]?release-channel=test-v2/auth/instagram/v2//code=12232131
In conclusion, I have no idea what to do with this new linking API. I hope I’ve done something wrong and that it isn’t issues with the SDK. Any pointers on what I’m doing wrong would be lovely.
Thanks
EDIT:
I realize I haven’t even started on the standalone linking yet :-/ I’ve previously relied on the following due to this issue
const standaloneSchemeLink = 'myappname://+';
const appRedirectUri =
Constants.appOwnership === 'standalone'
? standaloneSchemeLink + APIPathBuilder.instagramAuth()
: Constants.linkingUri + APIPathBuilder.instagramAuth();