Skip to content

Commit 15707e8

Browse files
committed
feat(oauth): added signIn and link for oauth
1 parent 90a2589 commit 15707e8

File tree

7 files changed

+151
-34
lines changed

7 files changed

+151
-34
lines changed

packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java

+66-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
import com.facebook.react.bridge.WritableArray;
3131
import com.facebook.react.bridge.WritableMap;
3232
import com.google.android.gms.tasks.OnCompleteListener;
33+
import com.google.android.gms.tasks.OnFailureListener;
34+
import com.google.android.gms.tasks.OnSuccessListener;
35+
import com.google.android.gms.tasks.Task;
3336
import com.google.firebase.FirebaseApp;
3437
import com.google.firebase.FirebaseException;
3538
import com.google.firebase.FirebaseNetworkException;
@@ -203,7 +206,6 @@ public void addIdTokenListener(final String appName) {
203206

204207
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
205208
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
206-
207209
if (!mIdTokenListeners.containsKey(appName)) {
208210
FirebaseAuth.IdTokenListener newIdTokenListener =
209211
firebaseAuth1 -> {
@@ -838,6 +840,45 @@ private void signInWithCredential(
838840
});
839841
}
840842
}
843+
@ReactMethod
844+
public void signInWithProvider(String appName, String providerId, @Nullable String email, Promise promise){
845+
OAuthProvider.Builder provider = OAuthProvider.newBuilder(providerId);
846+
if(email != null){
847+
provider.addCustomParameter("login_hint", email);
848+
}
849+
Activity activity = getCurrentActivity();
850+
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
851+
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
852+
853+
OnSuccessListener onSuccess = new OnSuccessListener<AuthResult>(){
854+
@Override
855+
public void onSuccess(AuthResult authResult) {
856+
Log.d(TAG, "signInWithProvider:onComplete:success");
857+
promiseWithAuthResult(authResult, promise);
858+
}
859+
};
860+
861+
OnFailureListener onFailure = new OnFailureListener(){
862+
@Override
863+
public void onFailure(@NonNull Exception e) {
864+
Log.w(TAG, "signInWithProvider:onComplete:failure", e);
865+
promiseRejectAuthException(promise, e);
866+
}
867+
};
868+
869+
870+
Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
871+
if(pendingResultTask != null){
872+
pendingResultTask
873+
.addOnSuccessListener(onSuccess)
874+
.addOnFailureListener(onFailure);
875+
} else {
876+
firebaseAuth
877+
.startActivityForSignInWithProvider(activity, provider.build())
878+
.addOnSuccessListener(onSuccess)
879+
.addOnFailureListener(onFailure);
880+
}
881+
}
841882

842883
/**
843884
* signInWithPhoneNumber
@@ -1866,6 +1907,30 @@ private void promiseWithAuthResult(AuthResult authResult, Promise promise) {
18661907
WritableMap authResultMap = Arguments.createMap();
18671908
WritableMap userMap = firebaseUserToMap(authResult.getUser());
18681909

1910+
if(authResult.getCredential() != null){
1911+
if(authResult.getCredential() instanceof OAuthCredential){
1912+
OAuthCredential creds = (OAuthCredential) authResult.getCredential();
1913+
WritableMap credentialMap = Arguments.createMap();
1914+
1915+
credentialMap.putString("providerId", creds.getProvider());
1916+
credentialMap.putString("signInMethod", creds.getSignInMethod());
1917+
1918+
if(creds.getIdToken() != null){
1919+
credentialMap.putString("idToken", creds.getIdToken());
1920+
}
1921+
1922+
if(creds.getAccessToken() != null){
1923+
credentialMap.putString("accessToken", creds.getAccessToken());
1924+
}
1925+
1926+
if(creds.getSecret() != null){
1927+
credentialMap.putString("secret", creds.getSecret());
1928+
}
1929+
1930+
authResultMap.putMap("credential", credentialMap);
1931+
}
1932+
}
1933+
18691934
if (authResult.getAdditionalUserInfo() != null) {
18701935
WritableMap additionalUserInfoMap = Arguments.createMap();
18711936

packages/auth/e2e/auth.e2e.js

+10-12
Original file line numberDiff line numberDiff line change
@@ -912,12 +912,11 @@ describe('auth()', function () {
912912
});
913913

914914
describe('signInWithPopup', function () {
915-
it('should throw an unsupported error', function () {
916-
(() => {
917-
firebase.auth().signInWithPopup();
918-
}).should.throw(
919-
'firebase.auth().signInWithPopup() is unsupported by the native Firebase SDKs.',
920-
);
915+
it('should trigger the oauth flow', async function () {
916+
await (async () => {
917+
const provider = new firebase.auth.OAuthProvider('oidc.react.com');
918+
await firebase.auth().signInWithPopup(provider);
919+
}).should.not.throw();
921920
});
922921
});
923922

@@ -1025,12 +1024,11 @@ describe('auth()', function () {
10251024
});
10261025

10271026
describe('signInWithRedirect()', function () {
1028-
it('should throw an unsupported error', function () {
1029-
(() => {
1030-
firebase.auth().signInWithRedirect();
1031-
}).should.throw(
1032-
'firebase.auth().signInWithRedirect() is unsupported by the native Firebase SDKs.',
1033-
);
1027+
it('should trigger the oauth flow', async function () {
1028+
await (async () => {
1029+
const provider = new firebase.auth.OAuthProvider('oidc.react.com');
1030+
await firebase.auth().signInWithRedirect(provider);
1031+
}).should.not.throw();
10341032
});
10351033
});
10361034

packages/auth/e2e/provider.e2e.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,7 @@ describe('auth() -> Providers', function () {
149149
describe('OAuthProvider', function () {
150150
describe('constructor', function () {
151151
it('should throw an unsupported error', function () {
152-
(() => new firebase.auth.OAuthProvider()).should.throw(
153-
'`new OAuthProvider()` is not supported on the native Firebase SDKs.',
154-
);
152+
(() => new firebase.auth.OAuthProvider('oidc.react.com')).should.not.throw();
155153
});
156154
});
157155

packages/auth/lib/User.js

+4-8
Original file line numberDiff line numberDiff line change
@@ -310,16 +310,12 @@ export default class User {
310310
);
311311
}
312312

313-
linkWithPopup() {
314-
throw new Error(
315-
'firebase.auth.User.linkWithPopup() is unsupported by the native Firebase SDKs.',
316-
);
313+
async linkWithPopup(provider) {
314+
return this.native.linkWithProvider(provider.providerId, provider.customParameters?.login_hint);
317315
}
318316

319-
linkWithRedirect() {
320-
throw new Error(
321-
'firebase.auth.User.linkWithRedirect() is unsupported by the native Firebase SDKs.',
322-
);
317+
async linkWithRedirect(provider) {
318+
return this.linkWithPopup(provider);
323319
}
324320

325321
reauthenticateWithPhoneNumber() {

packages/auth/lib/index.d.ts

+55-1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ export namespace FirebaseAuthTypes {
109109
credential: (token: string | null, secret?: string) => AuthCredential;
110110
}
111111

112+
export type OAuthProvider = AuthProvider & {
113+
new (providerId: string): OAuthProvider;
114+
setCustomParameters: (customOAuthParameters: object) => void;
115+
};
116+
112117
/**
113118
* Interface that represents an Open ID Connect auth provider. Implemented by other providers.
114119
*/
@@ -315,7 +320,7 @@ export namespace FirebaseAuthTypes {
315320
* firebase.auth.OAuthProvider;
316321
* ```
317322
*/
318-
OAuthProvider: AuthProvider;
323+
OAuthProvider: OAuthProvider;
319324
/**
320325
* Custom Open ID connect auth provider implementation.
321326
*
@@ -387,6 +392,12 @@ export namespace FirebaseAuthTypes {
387392
* Any additional user information assigned to the user.
388393
*/
389394
additionalUserInfo?: AdditionalUserInfo;
395+
396+
/**
397+
* The AuthCredential returned from the identity provider.
398+
*/
399+
credential: AuthCredential | null;
400+
390401
/**
391402
* Returns the {@link auth.User} interface of this credential.
392403
*/
@@ -1198,6 +1209,46 @@ export namespace FirebaseAuthTypes {
11981209
*/
11991210
linkWithCredential(credential: AuthCredential): Promise<UserCredential>;
12001211

1212+
/**
1213+
* Link the user with a 3rd party provider.
1214+
*
1215+
* #### Example
1216+
*
1217+
* ```js
1218+
* const oauthProvider = new firebase.auth.OAuthProvider('oidc.react.com')
1219+
* const authCredentials = await firebase.auth().currentUser.linkWithPopup(oauthProvider);
1220+
* ```
1221+
*
1222+
* @error auth/provider-already-linked Thrown if the provider has already been linked to the user. This error is thrown even if this is not the same provider's account that is currently linked to the user.
1223+
* @error auth/invalid-credential Thrown if the provider's credential is not valid. This can happen if it has already expired when calling link, or if it used invalid token(s). See the Firebase documentation for your provider, and make sure you pass in the correct parameters to the credential method.
1224+
* @error auth/credential-already-in-use Thrown if the account corresponding to the credential already exists among your users, or is already linked to a Firebase User.
1225+
* @error auth/email-already-in-use Thrown if the email corresponding to the credential already exists among your users.
1226+
* @error auth/operation-not-allowed Thrown if you have not enabled the provider in the Firebase Console. Go to the Firebase Console for your project, in the Auth section and the Sign in Method tab and configure the provider.
1227+
* @throws on iOS {@link auth.NativeFirebaseAuthError}, on Android {@link auth.NativeFirebaseError}
1228+
* @param provider A created {@link auth.AuthProvider}.
1229+
*/
1230+
linkWithPopup(provider: AuthProvider): Promise<UserCredential>;
1231+
1232+
/**
1233+
* Link the user with a 3rd party provider.
1234+
*
1235+
* #### Example
1236+
*
1237+
* ```js
1238+
* const oauthProvider = new firebase.auth.OAuthProvider('oidc.react.com')
1239+
* const authCredentials = await firebase.auth().currentUser.linkWithPopup(oauthProvider);
1240+
* ```
1241+
*
1242+
* @error auth/provider-already-linked Thrown if the provider has already been linked to the user. This error is thrown even if this is not the same provider's account that is currently linked to the user.
1243+
* @error auth/invalid-credential Thrown if the provider's credential is not valid. This can happen if it has already expired when calling link, or if it used invalid token(s). See the Firebase documentation for your provider, and make sure you pass in the correct parameters to the credential method.
1244+
* @error auth/credential-already-in-use Thrown if the account corresponding to the credential already exists among your users, or is already linked to a Firebase User.
1245+
* @error auth/email-already-in-use Thrown if the email corresponding to the credential already exists among your users.
1246+
* @error auth/operation-not-allowed Thrown if you have not enabled the provider in the Firebase Console. Go to the Firebase Console for your project, in the Auth section and the Sign in Method tab and configure the provider.
1247+
* @throws on iOS {@link auth.NativeFirebaseAuthError}, on Android {@link auth.NativeFirebaseError}
1248+
* @param provider A created {@link auth.AuthProvider}.
1249+
*/
1250+
linkWithRedirect(provider: Provider): Promise<UserCredential>;
1251+
12011252
/**
12021253
* Re-authenticate a user with a third-party authentication provider.
12031254
*
@@ -1708,6 +1759,9 @@ export namespace FirebaseAuthTypes {
17081759
*/
17091760
signInWithCredential(credential: AuthCredential): Promise<UserCredential>;
17101761

1762+
signInWithPopup(provider: AuthProvider): Promise<UserCredential>;
1763+
signInWithRedirect(provider: AuthProvider): Promise<UserCredential>;
1764+
17111765
/**
17121766
* Sends a password reset email to the given email address.
17131767
* Unlike the web SDK, the email will contain a password reset link rather than a code.

packages/auth/lib/index.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -360,16 +360,16 @@ class FirebaseAuthModule extends FirebaseModule {
360360
throw new Error('firebase.auth().setPersistence() is unsupported by the native Firebase SDKs.');
361361
}
362362

363-
signInWithPopup() {
364-
throw new Error(
365-
'firebase.auth().signInWithPopup() is unsupported by the native Firebase SDKs.',
366-
);
363+
signInWithPopup(provider) {
364+
return this.native
365+
.signInWithProvider(provider.providerId, provider.customParameters?.login_hint)
366+
.then(userCredential => this._setUserCredential(userCredential));
367367
}
368368

369369
signInWithRedirect() {
370-
throw new Error(
371-
'firebase.auth().signInWithRedirect() is unsupported by the native Firebase SDKs.',
372-
);
370+
return this.native
371+
.signInWithProvider(provider.providerId, provider.customParameters?.login_hint)
372+
.then(userCredential => this._setUserCredential(userCredential));
373373
}
374374

375375
// firebase issue - https://github.com/invertase/react-native-firebase/pull/655#issuecomment-349904680

packages/auth/lib/providers/OAuthProvider.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@
1818
const providerId = 'oauth';
1919

2020
export default class OAuthProvider {
21-
constructor() {
22-
throw new Error('`new OAuthProvider()` is not supported on the native Firebase SDKs.');
21+
constructor(providerId) {
22+
this.providerId = providerId;
23+
}
24+
25+
customParameters = {};
26+
27+
setCustomParameters(customParameters) {
28+
this.customParameters = customParameters;
2329
}
2430

2531
static get PROVIDER_ID() {

0 commit comments

Comments
 (0)