Skip to content
This repository has been archived by the owner. It is now read-only.

request: Add twitter auth example (ios with skipNativeAuth) #93

Closed
mesqueeb opened this issue Oct 6, 2021 · 7 comments
Closed

request: Add twitter auth example (ios with skipNativeAuth) #93

mesqueeb opened this issue Oct 6, 2021 · 7 comments
Assignees

Comments

@mesqueeb
Copy link
Contributor

mesqueeb commented Oct 6, 2021

Based on these docs:

https://github.com/robingenz/capacitor-firebase-authentication/blob/main/docs/firebase-js-sdk.md

I tried to implement Twitter:

  async function signinWithTwitter(): Promise<void> {
    // 1. Create credentials on the native layer
    const result: SignInResult = await FirebaseAuthentication.signInWithTwitter()
    if (!result.credential?.idToken || !result.credential?.secret) {
      throw new Error('Twitter error')
    }
    // 2. Create credentials on the web layer
    const credential = TwitterAuthProvider.credential(
      result.credential?.idToken,
      result.credential?.secret
    )
    // 3. Sign in on the web layer using the id token
    await signInWithCredential(firebaseAuth, credential)
  }

However, that doesn't work. The result looks like:

image

I don't get the idToken and secret.

It seems like Twitter works with redirect detection....?
I do see the redirection URL: do we need to parse something from here?

Screenshot 2021-10-07 at 0 23 20

All help much appreciated!

my config:

"FirebaseAuthentication": {
      "skipNativeAuth": true,
      "providers": [
        "apple.com",
        "google.com",
        "twitter.com"
      ]
    },
@mesqueeb mesqueeb changed the title request: Add twitter auth example request: Add twitter auth example (ios with skipNativeAuth) Oct 6, 2021
@robingenz robingenz self-assigned this Oct 6, 2021
@robingenz
Copy link
Owner

Oh, I will have to take a closer look at this. I'll try to find some time this weekend. Thank you for this report.
Does it work on Android?

@mesqueeb
Copy link
Contributor Author

mesqueeb commented Oct 7, 2021

@robingenz Update on Twitter Auth:

I was able to grab information from that super complex deeplink return URL (took me a couple of hours... 😅 ):

function getTwitterToken(url: string): { token: null | string; verifier: null | string } {
    if (!isFullString(url)) {
      return { token: null, verifier: null }
    }
    /**
     * @example "com.googleusercontent.apps.625543939572-45clgsm7vau24eualpnu9slvpst8lbcp://firebaseauth/link?deep_link_id=https%3A%2F%2Fcolorfulcasting-22977.firebaseapp.com%2F__%2Fauth%2Fcallback%3FauthType%3DsignInWithRedirect%26link%3Dhttps%253A%252F%252Fcolorfulcasting-22977.firebaseapp.com%252F__%252Fauth%252Fhandler%253Fstate%253DAMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ%2526oauth_token%253Di5AwREDACTEDfFjLB8c%2526oauth_verifier%253DVREDACTEDzdSpsiYfQ%26eventId%3Dsifmpamdqx"
     */
    const _url = url
    /**
     * @example "com.googleusercontent.apps.625543939572-45clgsm7vau24eualpnu9slvpst8lbcp://firebaseauth/link?deep_link_id=https://colorfulcasting-22977.firebaseapp.com/__/auth/callback?authType=signInWithRedirect&link=https%3A%2F%2Fcolorfulcasting-22977.firebaseapp.com%2F__%2Fauth%2Fhandler%3Fstate%3DAMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ%26oauth_token%3Di5AwREDACTEDfFjLB8c%26oauth_verifier%3DVREDACTEDzdSpsiYfQ&eventId=sifmpamdqx"
     */
    const urlUtf8 = decodeURIComponent(_url)
    /**
     * @example "deep_link_id=https://colorfulcasting-22977.firebaseapp.com/__/auth/callback?authType=signInWithRedirect&link=https%3A%2F%2Fcolorfulcasting-22977.firebaseapp.com%2F__%2Fauth%2Fhandler%3Fstate%3DAMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ%26oauth_token%3Di5AwREDACTEDfFjLB8c%26oauth_verifier%3DVREDACTEDzdSpsiYfQ&eventId=sifmpamdqx"
     */
    const outerQuery = urlUtf8.split('?').slice(1).join('?')
    /**
     * @example "https://colorfulcasting-22977.firebaseapp.com/__/auth/callback?authType=signInWithRedirect&link=https%3A%2F%2Fcolorfulcasting-22977.firebaseapp.com%2F__%2Fauth%2Fhandler%3Fstate%3DAMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ%26oauth_token%3Di5AwREDACTEDfFjLB8c%26oauth_verifier%3DVREDACTEDzdSpsiYfQ&eventId=sifmpamdqx"
     */
    const deepLinkId = outerQuery.replace(/.*deep_link_id=([^=]+)/, '$1')
    /**
     * @example "authType=signInWithRedirect&link=https%3A%2F%2Fcolorfulcasting-22977.firebaseapp.com%2F__%2Fauth%2Fhandler%3Fstate%3DAMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ%26oauth_token%3Di5AwREDACTEDfFjLB8c%26oauth_verifier%3DVREDACTEDzdSpsiYfQ&eventId=sifmpamdqx"
     */
    const innerQuery = deepLinkId.split('?')[1]
    /**
     * @example "https%3A%2F%2Fcolorfulcasting-22977.firebaseapp.com%2F__%2Fauth%2Fhandler%3Fstate%3DAMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ%26oauth_token%3Di5AwREDACTEDfFjLB8c%26oauth_verifier%3DVREDACTEDzdSpsiYfQ"
     */
    const linkOfInnerQuery = innerQuery.replace(/.*link=([^&]+)(&.*|)/, '$1')
    /**
     * @example "https://colorfulcasting-22977.firebaseapp.com/__/auth/handler?state=AMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ&oauth_token=i5AwREDACTEDfFjLB8c&oauth_verifier=VREDACTEDzdSpsiYfQ"
     */
    const linkUtf8 = decodeURIComponent(linkOfInnerQuery)
    /**
     * @example "state=AMbdREDACTEDnS-IYlUFuREDACTEDnn-xZssQfy-obREDACTEDjrlg_MfILVwREDACTEDwtEbkpL0l5a9RBrmDvn1DrFhgPQ&oauth_token=i5AwREDACTEDfFjLB8c&oauth_verifier=VREDACTEDzdSpsiYfQ"
     */
    const linkQuery = linkUtf8.split('?')[1] || ''

    const token = linkQuery.replace(/.*oauth_token=([^&]+)(&.+|)/, '$1')
    const verifier = linkQuery.replace(/.*oauth_verifier=([^&]+)(&.+|)/, '$1')

    console.log(`_url → `, _url)
    console.log(`urlUtf8 → `, urlUtf8)
    console.log(`outerQuery → `, outerQuery)
    console.log(`deepLinkId → `, deepLinkId)
    console.log(`innerQuery → `, innerQuery)
    console.log(`linkOfInnerQuery → `, linkOfInnerQuery)
    console.log(`linkUtf8 → `, linkUtf8)
    console.log(`linkQuery → `, linkQuery)
    console.log(`token → `, token)
    console.log(`verifier → `, verifier)

    return { token, verifier }
  }

However, having this "verifier" seems not enough. It's not the "secret":

  async function signinWithTwitterToken(token: string, verifier: string): Promise<void> {
    const credential = TwitterAuthProvider.credential(token, verifier)
    await signInWithCredential(firebaseAuth, credential)
  }

When I execute this I got:

image

I'm not sure what to do next. : S

@mesqueeb
Copy link
Contributor Author

mesqueeb commented Oct 7, 2021

@robingenz On Android it works as expected:

image

I get the proper info from your Library. So it must be just an iOS bug.

@mesqueeb
Copy link
Contributor Author

mesqueeb commented Oct 8, 2021

@robingenz I did some more digging and found this line:

           self.pluginImplementation.handleSuccessfulSignIn(credential: credential, idToken: nil, nonce: nil)

here: https://github.com/robingenz/capacitor-firebase-authentication/blob/main/ios/Plugin/Handlers/OAuthProviderHandler.swift#L45

I technically can't read Swift, so I'm not 100% sure, but to me this looks like you pass null for the idToken and nonce.

Your Twitter implementation is OAuth based and requires an "accessToken" and "secret", so I guess you need to write extra code and properly pass them to the handleSuccessfulSignIn ?

I guess you just overlooked it? 😅

@robingenz
Copy link
Owner

Thanks for looking it up.
The access token and secret should be added here.
So it is correct that I pass nil there, because I can pick it up later.
I may find some time this weekend to debug this.

@mesqueeb
Copy link
Contributor Author

@robingenz let me know if there's anything I can help you with this weekend.

@robingenz
Copy link
Owner

I just took a closer look.
It seems that the access token and the secret are added to the credential object only after the native authentication.
The Firebase documentation includes the following example:

    provider.getCredentialWith(nil) { credential, error in
      if error != nil {
        // Handle error.
      }
      if credential != nil {
        Auth.auth().signIn(with: credential) { authResult, error in
          if error != nil {
            // Handle error.
          }
          // User is signed in.
          // IdP data available in authResult.additionalUserInfo.profile.
          // Twitter OAuth access token can also be retrieved by:
          // authResult.credential.accessToken
          // Twitter OAuth ID token can be retrieved by calling:
          // authResult.credential.idToken
          // Twitter OAuth secret can be retrieved by calling:
          // authResult.credential.secret
        }
      }
    }

As far as I know there is nothing I can do about it. For this reason, I am closing this Issue.

However, I have found a workaround:
I was able to log in with the Firebase JS SDK after setting skipNativeAuth to false. So you first log in natively to Firebase and then to the web. Unfortunately this does not work with all providers, since you can't use credentials twice with some providers. Therefore I don't know if this is a workaround for you.
I could imagine extending the skipNativeAuth option to allow configuration for individual providers. However, for this I would create a new feature request.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants