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

Linking custom OAuth providers with existing Firebase user #10

Open
CoderSpinoza opened this issue Sep 14, 2017 · 10 comments
Open

Linking custom OAuth providers with existing Firebase user #10

CoderSpinoza opened this issue Sep 14, 2017 · 10 comments

Comments

@CoderSpinoza
Copy link
Contributor

For officially supported OAuth providers such as Google, Facebook, Twitter, and Github, it is possible to link them to an existing Firebase user using FirebaseUser.linkWithCredential() method. However, it does not seem easy for custom OAuth providers to be linked with existing Firebase user since only signInWithCustomToken() method is supported for custom OAuth providers, not linkWithCredential(). Under this circumstance, I have two questions.

  1. Is there a way for unofficial providers to link accounts by creating credentials using OAuthProvider.getCredential() method? Currently when I try to create an AuthCredential object, I get this exception in Android.
com.google.firebase.FirebaseException: An internal error has occurred. [ INVALID_PROVIDER_ID:Provider Id is not supported. ]
  1. If 1) is not possible, what would be the suggested way of linking custom OAuth provider with the given Firebase user, say a user with facebook and google already linked?

For example, I would want a user to link all google, facebook, and instagram accounts since the service I am working on wants to post a given picture to all platforms. If this is not possible, developers would be reluctant to solely depend on Firebase authentication platform for managing users. I would appreciate any help or guide :)

@CoderSpinoza CoderSpinoza changed the title Linking custom OAuth providers with existing Linking custom OAuth providers with existing Firebase user Sep 14, 2017
@samtstern
Copy link
Contributor

@CoderSpinoza thanks for reporting this. Can you show the code you are using with OAuthProvider? If you're passing in something like instagram to this it will not work. We don't yet support custom provider IDs.

@The-Alchemist
Copy link

The-Alchemist commented Jan 23, 2018

I'm also interested in using a custom OAuth provider (https://www.schoology.com/). I'm surprised there isn't an integration point for custom OAuth providers.

Looks like there's plans to allow it, but unfortunately no timeline (https://groups.google.com/d/topic/firebase-talk/7u-VTlbJrms/discussion).

I don't mind sending a PR if someone points me in the right direction...

@olegdater
Copy link

Any update on this? Is it still not possible to link custom OAuth providers with official login providers?

@nicolasgarnier
Copy link
Contributor

tldr; Yes it is possible to "Link" an official OAuth provider with a Custom token sign in mechanism. However it's not really "linking" but you can do something that looks like it.

For the custom providers that we're demonstrating in this repo we're generating a custom token that allow to sign-in with an account of the given UID. I think there is some confusion with what a custom token allows you to do. Let me try to explain by going through the 2 scenarios and how you could implement something that is similar than "linking":

Official Provider first

Let's go through the flow of when a user first creates an account using an official provider (e.g. Facebook/Google) and THEN signs-in with a custom provider:

The user has signed in with Google/Facebook First in the past. This creates an account that is "marked" as being enabled for Google/Facebook for a specific Google/Facebook User ID.

Normally when a user want to link an account (e.g. Links a Google with a Facebook account) he will first have to sign in with the Existing provider (e.g. Google) and also provide a Facebook Credentials then we'll mark the two as being linked. We need to try to replicate this behavior for a custom provider.

In this scenario the user will sign in with a custom auth provider (e.g. Line). Since we are signing-in the user by generating a custom token it can simply work right away by generating a custom token for the existing user with the same email address (e.g. search for existing users with (getUserByEmail())[https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth#getUserByEmail]). The admin SDK allows you to simply generate the custom token without any checks. However this is not the recommended path for a user security perspective. Because you should not trust that both account are controlled by the same person you should first ask the user to sign-in with his existing account:

  1. On the server side you check if an account with the same email already exists using (getUserByEmail)[https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth#getUserByEmail]
  2. An account exists: If the user is not marked as being enabled for the custom Provider (e.g. Line, see next step) you must ask the user to sign-in using the existing account first to prove ownership (e.g. Facebook or Google)
  3. Now the user is signed-in via Facebook/Google you can "mark" the account to be enabled for the custom provider too (e.g. Line) and save the Line User ID. You can use any sort of database you want to save that information but I think the best is to set a custom user claim (see setCustomUserClaim()) this ways the info stays attached to the user object directly and this saves requests. setCustomUserClaim({lineUID: lineMid})

Effectively you implemented your own "Linking" by checking Line is enabled on the account and making sure the Line User ID match what you have saved.

Custom Provider first

If a user creates an account using a custom provider first (e.g. Line) and tries to sign-in using a Google/Facebook account that has the same email things are easier since you can use the JS SDK to link the accounts by:

  1. User signs in Using Google/Facebook. You get an error that a user already exists. Keep the AuthCredential object in memory.
  2. Prompt the user to sign-in using the custom provider (e.g. Line). You get back a Custom token which you use to sign-in via signInWithCustomToken()
  3. Now the user is signed in via a custom token you can link the two accounts using linkWithCredential().

The current samples are mono-providers for simplicity.

By the way just a reminder: using the Firebase Console, you have the option to allow multiple accounts with the same email address which gets rid of all the issues related to Linking. In this case a Google account aaa@bbb.com will be different from a Facebook account with the same email address aaa@bbb.com, they will have different Firebase UID.

CoderSpinoza added a commit to CoderSpinoza/custom-auth-samples that referenced this issue Apr 9, 2018
Exhibit better ways to link custom oauth providers for users already
signed with built-in providers. The current best way to do so is
organized in the github issue FirebaseExtended#10 below:

FirebaseExtended#10

Admin.auth.Auth.setCustomUserClaims(uid, customUserClaims) was added for
setting custom data for control access.

TODO: As mentioned in the above issue, clients should ensure that the
same user is previously signed in with built-in providers
(facebook or google), but this is omitted in the sample. It is each
developer's responsibility to ensure this for security.

Signed-off-by: Hara Kang <hara0115@gmail.com>
@rromanchuk
Copy link

Hey @nicolasgarnier, let's say i'm using an official provider, which the idToken is then passed via REST to traditional backend, verified, and identity claimed based on the identifiers included in the jwt payload.

We aren't using these firebase accounts to access any firebase resources, but just to offload the identity provider burden. There are some administrative use cases where I'd like to have account parity from an event chain that does not involve the client.

I made a simple service/utility for things like account removal, triggering email changes/verification, and I got this working fine, but it's starting to smell.
https://firebase.google.com/docs/reference/rest/auth/

To test, i simply grabbed a few of my test accounts refreshTokens from console in order to exchange it for an idToken to make these requests. What's the best way to handle to handle a case that is unrelated to client communicating with the server via REST, like an administrator/job needs to remove an account. In this hypothetical, let's just assume the idToken has expired, short of passing refreshTokens around, is there anything else i'm missing? I have the firebase_uid, i have service admin service creds, i just don't have anything to offer to generate a fresh idToken to take actions. This looks like what i need https://firebase.google.com/docs/reference/rest/auth/#section-verify-custom-token

I'm already set up to encode my own jwt payloads against my google service account but that doesn't make sense to me in this context. I think i'm just conflating how the admin SDK works, with this REST api, which actually looks like what the high level clients are interfacing with. Now that I think about it, this isn't even using my service account (just looked at how i'm creating dynamiclinks) to construct the requests, so of course i'm not going to be able to just do what ever i want. Ok i'm going to stop talking to myself and RTFM

@hanniiel
Copy link

any updates?

@cavico
Copy link

cavico commented Mar 21, 2021

any updates? following up

@geminiyellow
Copy link

looks nothing change

@abinhho
Copy link

abinhho commented Mar 14, 2024

Any updates?

@Rimantovas
Copy link

Any news?

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

No branches or pull requests