Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Social Authentication not working on Ionic #3537

Open
oliverandersencox opened this issue Jun 24, 2019 · 50 comments
Open

Social Authentication not working on Ionic #3537

oliverandersencox opened this issue Jun 24, 2019 · 50 comments
Assignees
Labels
Auth Related to Auth components/category feature-request Request a new feature Ionic Related to Ionic Framework

Comments

@oliverandersencox
Copy link

The docs tell us we can use federated sign in like so:

federatedSignIn('facebook')

To create a cognito user from facebook OAuth. However on a device with Ionic, the redirection process is broken.

In the browser, the process works great, however on IOS or Android it does not.

once the authentication is done, we cannot redirect back to localhost as it won't go back to the app.

If you set the redirect URI to the apps url schema, the redirection does work, however the authentication system does not pick this up when the app is opened from the login redirect.

I have in place a function that can detect the URL being used to open the app and it is correctly opening the app with the appended token information in the redirect URL.

However Amplify does not pick this up. I then tried implementing the HUB to detect auth changes and again this had no effect. Once the redirect away to the Amplify federated login page occurs, it effectively breaks the process.

It is possible to fix this by using the Facebook Ionic wrapper or the Google auth wrapper, however this creates a federated identity which then means you cannot read and write using the API.

Any advice on this would be great as this is a real blocker. Is there a way to take the redirect tokens and pass them to amplify manually? This would solve the problem.

The goal is to be able to create a cognito user in the Amplify pool, from the social providers.

@kaustavghosh06 kaustavghosh06 transferred this issue from aws-amplify/amplify-cli Jun 26, 2019
@powerful23 powerful23 added Auth Related to Auth components/category Ionic Related to Ionic Framework to-be-reproduced Used in order for Amplify to reproduce said issue labels Jun 27, 2019
@giacomocarrozzo
Copy link

Hi @oliverandersencox!
It's 3 days that I'm fighting with completely the same issue. I'm developing an app with Ionic 5.0.3 and aws-amplify. I used this tutorial to help me developing it: Tutorial
Here the tutorial's source code: Source code

The first issue to solve was to find a way to redirect URI into Ionic app after Facebook Login with the Browser.
I solved this issue with this plugin: Deeplinks
But, like you said, I'm not able to let Hub Service detect the redirect call.
Did you find a solution to this problem?
If yes would you mind to share it with me?

@oliverandersencox
Copy link
Author

@giacomocarrozzo I gave up in the end!

There has been no response from any of the devs on this issue so I thought I'd wait it out.

I managed to get it working using the facebook and google ionic native packages - but as I said, that creates identities and not a cognito user which makes it pretty much useless!

@giacomocarrozzo
Copy link

giacomocarrozzo commented Jul 1, 2019

Yes, I'm trying to avoid the facebook and google native packages since I would like to fully manage users with AWS Cognito. Did you use Deeplinks to redirect URI to the App?
Here my constructor's AppComponent code:

this.platform.ready().then(() => {
  this.deeplinks.route({
    '/auth': AuthComponent,
    '/auth/signin': SignInComponent
   }).subscribe((match) => {
    // match.$route - the route we matched, which is the matched entry from the arguments to route()
    // match.$args - the args passed in the link
    // match.$link - the full link data

    this.router.navigate(['/auth'], { queryParams: { code: match.$args['code'], state: match.$args['state']  } });
    alert( "MATCH" + JSON.stringify(match));
  },
  (nomatch) => {
    // nomatch.$link - the full link data
    alert("NOTMATCH" + JSON.stringify(nomatch));
  });
  
});

"match.$args" cointains Aws Cognito get params.
Like you see I'm able to catch the redirect call and I'm able to catch code and state parameters, but Hub is not receive my call.

@oliverandersencox
Copy link
Author

@giacomocarrozzo yes I did the same with the redirect. Any word on this from the devs?

@giacomocarrozzo
Copy link

No @oliverandersencox , I'm still waiting for an answer. I hope to get it soon otherwise I have to switch to another sign-up platform.

@amburt05
Copy link

Yea, I'm having the same issue. I don't see a way to use the hosted UI with ionic. It's become a huge blocker for me.

@RSchumacher13
Copy link

Same here, blocked from using hosted ui with Ionic, However we need custom scopes.

@amburt05
Copy link

amburt05 commented Aug 23, 2019

I think this issue is related -> #3386

Edit: I just realized it was created by the same user. Obviously, still an issue though, but could be consolidated?

Edit2: Two more issues that could be related :
#3389
#2455

@oliverandersencox
Copy link
Author

@amburt05 yes it is the same issue. I've been waiting on a fix for this for months now. It seems there a fix in a pull request but its hasnt been reviewed yet

@tmburt04
Copy link

Any update on this?

@oliverandersencox
Copy link
Author

@haverchuck can we get some sort of feedback on this. Most apps built with Ionic need this feature, and it seems there has been no comment on any of the Social Auth threads for Ionic.

@oliverandersencox
Copy link
Author

@giacomocarrozzo have you had any luck here? I am going to try one approach today and hopefully get around this MASSIVE BLOCKER.

@tmburt04
Copy link

Please post your solution if you figure it out @oliverandersencox . This is brick-walling my deployment, as well as everyone else' I'm sure.

@giacomocarrozzo
Copy link

@oliverandersencox I didn't try to solve this issue anymore. If you take some step ahead and you would like to share it, I'll be happy to try to help you.

@amburt05
Copy link

Is there really zero feedback from the AWS team on this? We're trying to do some testing and are getting ready to just drop AWS cognito. This is kind of ridiculous. Do they just open source the stuff they just don't feel like dealing with?

@oliverandersencox
Copy link
Author

@amburt05 I've been trying to get as response on this and other posts for weeks now.

check this - #3279

But to me it doesnt answer whether it will work with Ionic on device

@sammartinez sammartinez added question General question and removed to-be-reproduced Used in order for Amplify to reproduce said issue labels Oct 30, 2019
@sammartinez
Copy link
Contributor

@oliverandersencox Apologize that we haven't replied on this issue. I did reference an open Pull Request (PR) for adding federated sign in for Ionic and Angular.. I am also seeing yourself comment on that Feature Request. We are following up with the person that cut the PR to see where it is at. I do want to know, can you provide the link to the documentation you are referring to?

@sammartinez sammartinez self-assigned this Oct 30, 2019
@oliverandersencox
Copy link
Author

@sammartinez is there any info you can give us on this. The user is created in the user pool, the only issue is simply the redirect doesn't do any auth checks or pick up this new user and sign in.

There must be some advice on manually detecting once redirected?

@oliverandersencox
Copy link
Author

@@giacomocarrozzo I finally got it working!!

So the reason the authentication is not registered is because the Ionic webview is not loaded with the state and code from the redirect. These need to be passed to Ionic in order for Amplify to run its magic.

In order to do so you need to add redirect URL's top the app and then intercept these deep links. In my case im using capacitor, which handles the deep links so I can grab the data:

   App.addListener('appUrlOpen', (data: any) => {
      console.log('App opened with URL: ' + data.url);
      this.deeplinks.consumeDynamicLink(data.url);
    });

From this point I now have the redirect query params passed back by Facebook and google. Now I need to load the application into the webview again but this time with the query params appended to it:

document.location.href = capacitor://localhost/authevent/?code=${queryParams.code}&state=${queryParams.state};

The next step is to ensure you have the amplify hub set up, as for some reason the auth state observable doesn't notice the event even after this.

   Hub.listen("auth", ({ payload: { event, data } }) => {
      if (event === 'signIn') {
        this.auth.setAuthstate(true);
        this.userService.listenToSocialAuth(data.username);
      }
    });

At this point I have the facebook auth up and running.

@giacomocarrozzo
Copy link

giacomocarrozzo commented Nov 10, 2019

@oliverandersencox awesome! it's working to me too!

I just have these errors when I log out after a Social Auth:

[ERROR] 49:50.195 OAuth - Error handling auth response. Error: invalid_grant

Unhandled Promise rejection: Cannot read property 'accessToken' of undefined ; Zone: <root> ; Task: Promise.then ; Value: TypeError: Cannot read property 'accessToken' of undefined

It that working for you?

@oliverandersencox
Copy link
Author

@giacomocarrozzo so I also had that. If you run it incognito mode, you wont get that issue.

It seems cognito saves session data about the federated user, so that if you are removing and adding users in development it will throw this error.

Try running in incognito the error should disappear.

@oliverandersencox
Copy link
Author

is there any update on this. It would be great if there was a way to manually pass the state and token to authenticate rather than having to reload the entire app, as this could be done with a browser pop over for a way better UX

@pedramp20
Copy link

@florian-sander I am using React + Capacitor as well and the authentication fails on Android. What version of amplify do you use and are you doing anything else beside setting document.location.href ?

@shekhartupe
Copy link

shekhartupe commented Feb 18, 2021

I got this working with ionic angular on iOS. 4 basic tenets of this implementation:

  1. Setup cognito with Callback URL(s) matching your deeplinks and entries in aws-exports.js.
  2. Define (or generate via amplify-cli) aws-exports.js. Key here is redirectSignIn url should launch app via deep linking (tenet# 3)
  3. Implement deeplinking to handle the incoming queryString. Key here is to reload the app using window.location.href passing the same queryString for amplify to do its magic.
  4. Update config.xml to set iosScheme (Scheme for android) to match your deeplink scheme and allow-navigation to the new scheme. This point is not explicitly mentioned in any documentation I referred to POC this.

Links I referred with slight changes to implementation as needed:
https://medium.com/@tobinc/create-a-multi-platform-app-using-ionic-4-aws-amplify-in-app-oauth-with-social-idp-deep-linking-6b8de9bc6878
https://medium.com/@zippicoder/setup-aws-cognito-user-pool-with-an-azure-ad-identity-provider-to-perform-single-sign-on-sso-7ff5aa36fc2a
https://arjunsk.medium.com/cognito-hosted-ui-with-amplify-in-angular-7-26c9285675c4
And bunch of open issues on this topic on github.
Thanks for all contributors.

Key code snippets:

    // Used for listening to login events
    Hub.listen("auth", ({ payload: { event, data } }) => {
      console.log("Hub.listen event", event, data, JSON.stringify(data));
      if (event === "cognitoHostedUI" || event === "signedIn") {
        this.zone.run(() => this.router.navigate(['/home']));
      }
    });

    //currentAuthenticatedUser: when user comes to login page again
    Auth.currentAuthenticatedUser()
      .then(() => {
        console.log("Auth.currentAuthenticatedUser");
        this.router.navigate(['/home'], { replaceUrl: true });
      }).catch((err) => {
        console.log(err);
      })

  private setupDeepLinks(){
    if (this.platform.is('cordova')) {
      this.deeplinks.route({
        '/login':'/login'
      }).subscribe(match => {
        console.log('Success: ', match.$route, JSON.stringify(match.$link), JSON.stringify(match.$args));
                
        const internalPath = `${match.$route}?${match.$link.queryString}`;
        console.log("internalPath", internalPath);
        window.location.href = internalPath;
      },noMatch => {
        console.error('Error: ', noMatch);
      });
    }
  }

config.xml

    <allow-navigation href="iacdapp://*" />
    <preference name="iosScheme" value="iacdapp" />

aws-exports.js

        "redirectSignIn": "iacdapp://localhost/login",
        "redirectSignOut": "iacdapp://localhost/login",

@pedramp20
Copy link

pedramp20 commented Feb 18, 2021

@shekhartupe Thank you for your quick response. I was doing all the steps you mentioned. However, it didn't work for me.

There are a couple of issues that I solved to get it working.

  • Apps running in Capacitor have their default origin which is capacitor://localhost on iOS and http://localhost on Android. So the only way for Amplify to be triggered on redirection is to use the built-in deeplink listener, extract the parameters and call the default origin with the same query parameters. The problem is that due to CORS restriction. The authentication would fail.

  • If the app is reloaded by setting window.location.href, with the origin Amplify expects (the redirect uri registered in Cognito) then the CORS issue is resolved. Nevertheless, in my case Amplify was not being triggered and possibly an infinite loop can be created.

  • I had to call _handleAuthResponse directly to trigger amplify and add a parameter to the query and check it to avoid a loop

CapApp.addListener("appUrlOpen", (data) => {

  const params = new URLSearchParams(data.url.split("?")[1])

  if(params.has("local")){ // flag added to avoid a loop
    return
  }

  if (params.has("code") && params.has("state")) {
    const url = `${redirectUri}?code=${params.get("code")}&state=${params.get("state")}&local=${true}`

    document.location.href = url
    Auth._handleAuthResponse(url)
  }
});

And of course add the Amplfy Hub listener and act on different Auth events.

@jcardus
Copy link

jcardus commented Feb 22, 2021

I managed to get it working replacing capacitor:// with http://, looks like handleAuthResponse expects http or https.

Here's my working code:

import { Auth } from '@aws-amplify/auth'
import { Plugins } from '@capacitor/core'
const { App } = Plugins

App.addListener('appUrlOpen', async (data) => {
console.log(await Auth._handleAuthResponse(data.url.replace('capacitor://', 'http://')))
});

@foochuanyue
Copy link

I cannot seem to call Auth._handleAuthResponse(url).

It says the property is private. Is there a work around for this?

@chrisbonifacio chrisbonifacio self-assigned this Sep 14, 2021
@chrisbonifacio chrisbonifacio added this to Pending Triage in Issues Triaging via automation Sep 14, 2021
@chrisbonifacio chrisbonifacio moved this from Pending Triage to Investigating in Issues Triaging Sep 14, 2021
@jimmyl-cgair
Copy link

I cannot seem to call Auth._handleAuthResponse(url).

It says the property is private. Is there a work around for this?

I have the same problem. Do you have a fix or other way to make this works?

@jimmyl-cgair
Copy link

I cannot seem to call Auth._handleAuthResponse(url).
It says the property is private. Is there a work around for this?

I have the same problem. Do you have a fix or other way to make this works?

Instead of Auth._handleAuthResponse(url);

Try like that :

(Auth as any)._handleAuthResponse(url);

That helps me a lot.

@marcangelx
Copy link

Have you guys found an effective solution to address this issue? It appears that the solutions provided above may no longer be effective. I've been searching for methods to enable social authentication in Ionic for both Android and iOS platforms. Your insights on this matter would be greatly valued.

@jimmyl-cgair @KevinToala

@KevinToala
Copy link

Hi @marcangelx

I currently use the latest version of amplify 5.3.10 and we are working without issues in production with web, android and ios. I had to do a few more tweaks to make it work, but it's very similar to my last comment.
We use Angular + Ionic + Capacitor.

Here's how we make it work:

async federatedSignIn(provider: 'Facebook' | 'Google' | 'SignInWithApple') {
    // @ts-ignore
    await Auth.federatedSignIn({provider, customState: this.redirectUrl ? this.redirectUrl : this.router.url});
  }
  private initializeListenersForLogin() {
    const isWebPlatform = !Capacitor.isNativePlatform();
    if (!isWebPlatform) {
      App.addListener('appUrlOpen', ({url}) => {
        if (url.includes('/loginCallback')) {
          if (window && typeof window.history !== 'undefined') {
            this.saveWindowHistoryReplaceStateFunction = window.history.replaceState;
            window.history.replaceState = () => {};
          }

          // @ts-ignore
          // eslint-disable-next-line no-underscore-dangle
          (Auth as any)._handleAuthResponse(url);

          if (PLATFORM === 'ios') {
            Browser.close();
          }
        } else {
          const path = url.split('myapp.com').pop();
          if (path) {
            this.router.navigateByUrl(path);
          }
        }
      });
    }

    Hub.listen('auth', async ({payload: {event, data}}) => {
      if (isWebPlatform) {
        if (event === 'customOAuthState') {
          this.navController.navigateRoot(decodeURIComponent(data), {replaceUrl: true});
        }
      } else {
        if (event === 'signIn') {
          this.userService.changeUserStatusAuthentication(true);
        } else if (event === 'customOAuthState') {
          if (window && typeof window.history !== 'undefined') {
            window.history.replaceState = this.saveWindowHistoryReplaceStateFunction;
          }

          const loading = await this.loadingController.create({message: 'Loading...'});
          loading.present();

          this.router.navigateByUrl(decodeURIComponent(data), {replaceUrl: true})
            .finally(() => loading.dismiss());
        }
      }
    });
  }

amplify oauth config

const isWebPlatform = !Capacitor.isNativePlatform();
const redirectSignIn = isWebPlatform ? 'http://localhost:8100/loginCallback' : 'com.myapp.app://myapp.com/loginCallback';
const redirectSignOut = isWebPlatform ? 'http://localhost:8100' : 'com.myapp.app://myapp.com/logout';

const amplifyConfig = {
 amplify: {
    oauth: {
      domain: '=================.auth.us-east-1.amazoncognito.com',
      scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
      redirectSignIn,
      redirectSignOut,
      responseType: 'code',
      urlOpener: async (url) => {
        await Browser.open({url, windowName: isWebPlatform ? '_self' : '_blank'});
      }
    },
  }
}

I hope it helps you

@KevinToala
Copy link

Also important to have configured the url schema and deeplinks/universal link for android and ios.
In my case with Capacitor it would be with the following configurations:
https://capacitorjs.com/docs/apis/app
https://capacitorjs.com/docs/guides/deep-links

@naiduyanda
Copy link

  for me, it is navigating back to the application with the error " No Current User" 
  in android/app/src/main/AndroidManifest.xml file i add this configuration
  
    <activity android:name="com.amazonaws.mobile.auth.ui.SignInActivity" android:exported="true">
<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <!-- Define your custom URL scheme here -->
    <data android:scheme="custom-url-scheme"/>
</intent-filter>

@nadetastic nadetastic self-assigned this Sep 19, 2023
@keygun-development
Copy link

I'm a bit late, but it might help others. I was being redirected back to my app after trying to authenticate and when checking the logs it stopped at "set credentials from session". I'm using capacitor in the project and in my capacitor config file I had the CapacitorHTTP plugin enabled. After disabling the plugin it resolved the issue.

Correct me if I'm wrong, but I think it has to do with CapacitorHTTP sending CORS-free requests and this isn't accepted by AWS.

@alex-breen
Copy link

With AWS Amplify v6 and capacitor, Amplify Auth works for me. I'll share my implementation in case it is helpful to some.

  • Set up universal links as documented here: https://capacitorjs.com/docs/guides/deep-links
  • On the js file where you have Amplify Auth, import @capacitor/app and add a listener for appUrlOpen.
  • In your listener, if your are on Android call: window.location.replace(data.url)
  • In your listener, if you are on iOS, call: window.location.replace(data.url.replace('https', 'capacitor'))
  • In my situation, I code on windows, and pull latest via github onto my mac. So I need to run npx cap sync ios anytime dependencies in package.json change, otherwise imports won't work. Also, the domain for applinks on iOS seems to get cached, so set ?mode=developer if you are making updates to the site association file so it reads the latest.

@ryanweaver718
Copy link

Any solutions for v6 yet? I tried @alex-breen's solution but when I have universal links working with ios, the redirect from the hosted ui doesn't trigger the app opening, instead it opens in the safari browser, whereas if I click a link in a message or email it does open the app. Any solutions?

@AakashKB
Copy link

AakashKB commented May 8, 2024

I also have the issue of redirect is coming from a different origin.... I am unable to add capacitor://<url> format to my API credentials because only http and https are supported.

@AakashKB
Copy link

AakashKB commented May 8, 2024

^ solved, just adding the https format to callbacka and logout urls worked (this is on Amplify Gen 2)

But now I'm having an issue similar to @ryanweaver718.

On first try, it works and redirects back to app authenticating! But if I try using sign in via google again, it breaks in subsequent times, it redirects to browser, and I ahve to manually copy redirect link to my notes app and click it for it to go to app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Auth Related to Auth components/category feature-request Request a new feature Ionic Related to Ionic Framework
Projects
No open projects
Issues Triaging
Investigating
Development

No branches or pull requests