Issues with new Linking URI in SDK 27


#1

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:

  1. 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/

  1. 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]

  1. 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]

  1. 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();

#2

Hi there!

So in SDK 27 and beyond, you should be using Linking.makeUrl() to generate deep links to your app, and Linking.parse() to retrieve metadata from linking events you receive.

I believe the github issue you linked was resolved by these changes, but I’m going to check with @esamelson before officially closing it, because I want to be sure about that.


#3

Hey @ben, thanks for getting back to me :smiley:

So I tried using Linking.makeUrl, and ran into a new issue.

Same code as above, but with the following change:

// const appRedirectUri = Constants.linkingUri + APIPathBuilder.instagramAuth();
const appRedirectUri = Linking.makeUrl(APIPathBuilder.instagramAuth());

iOS:
Works on dev, it generates `exp://localhost:19000/–/auth/instagram/v2

On a published project, however, it doesn’t work. No errors, the webbrowser just redirects a couple of times, ending on a blank page and the Expo app reloades the project if the browser is dismissed. It generated a URL like this:

exp://exp.host/@[USER]/[PROJECT]/--/auth/instagram/v2?release-channel=test-v2

Android
Also works on dev, but not on published project. Getting blue “Something went wrong.” screen, saying

"No experience found at
exp://exp.host/@[USER]/[PROJECT]?release-channel=test-v2/auth/instagram/v2/

Notice the switcharoo between the path and release channel param. I assume it’s the same problem on iOS, but that the error is displayed differently.

It’s wierd, because if I just look at the appRedirectUri value, it looks fine (same as iOS above):

exp://exp.host/@[USER]/[PROJECT]/--/auth/instagram/v2?release-channel=test-v2

What could the issue be?


#4

Hey there, it looks like our SDK is generating the correct url, i.e. exp://exp.host/@[USER]/[PROJECT]/--/auth/instagram/v2?release-channel=test-v2

But whatever web page you’re directing to is generating the wrong url back: exp://exp.host/@[USER]/[PROJECT]?release-channel=test-v2/auth/instagram/v2/

^ This 2nd thing is not valid, it looks like it appended the url path onto the release channel query parameter.

Can you check the code on your auth web page and make sure it knows how to use Expo’s redirect urls properly?


#5

You’re right, the issue was on the backend. Thanks for helping out :slight_smile:


closed #6

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.