Skip to content

Commit

Permalink
feat(oauth): added signIn and link for oauth
Browse files Browse the repository at this point in the history
  • Loading branch information
Aetherall authored and Cedric committed Apr 11, 2023
1 parent 90a2589 commit 4a5a861
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseException;
import com.google.firebase.FirebaseNetworkException;
Expand All @@ -56,6 +59,7 @@
import com.google.firebase.auth.MultiFactorResolver;
import com.google.firebase.auth.MultiFactorSession;
import com.google.firebase.auth.OAuthProvider;
import com.google.firebase.auth.OAuthCredential;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthOptions;
import com.google.firebase.auth.PhoneAuthProvider;
Expand Down Expand Up @@ -203,7 +207,6 @@ public void addIdTokenListener(final String appName) {

FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);

if (!mIdTokenListeners.containsKey(appName)) {
FirebaseAuth.IdTokenListener newIdTokenListener =
firebaseAuth1 -> {
Expand Down Expand Up @@ -839,6 +842,87 @@ private void signInWithCredential(
}
}

@ReactMethod
public void signInWithProvider(String appName, String providerId, @Nullable String email, Promise promise){
OAuthProvider.Builder provider = OAuthProvider.newBuilder(providerId);
if(email != null){
provider.addCustomParameter("login_hint", email);
}
Activity activity = getCurrentActivity();
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);

OnSuccessListener onSuccess = new OnSuccessListener<AuthResult>(){
@Override
public void onSuccess(AuthResult authResult) {
Log.d(TAG, "signInWithProvider:onComplete:success");
promiseWithAuthResult(authResult, promise);
}
};

OnFailureListener onFailure = new OnFailureListener(){
@Override
public void onFailure(@NonNull Exception e) {
Log.w(TAG, "signInWithProvider:onComplete:failure", e);
promiseRejectAuthException(promise, e);
}
};


Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
if(pendingResultTask != null){
pendingResultTask
.addOnSuccessListener(onSuccess)
.addOnFailureListener(onFailure);
} else {
firebaseAuth
.startActivityForSignInWithProvider(activity, provider.build())
.addOnSuccessListener(onSuccess)
.addOnFailureListener(onFailure);
}
}

@ReactMethod
public void linkWithProvider(String appName, String providerId, @Nullable String email, Promise promise){
OAuthProvider.Builder provider = OAuthProvider.newBuilder(providerId);
if(email != null){
provider.addCustomParameter("login_hint", email);
}
Activity activity = getCurrentActivity();
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();

OnSuccessListener onSuccess = new OnSuccessListener<AuthResult>(){
@Override
public void onSuccess(AuthResult authResult) {
Log.d(TAG, "linkWithProvider:onComplete:success");
promiseWithAuthResult(authResult, promise);
}
};

OnFailureListener onFailure = new OnFailureListener(){
@Override
public void onFailure(@NonNull Exception e) {
Log.w(TAG, "linkInWithProvider:onComplete:failure", e);
promiseRejectAuthException(promise, e);
}
};


Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
if(pendingResultTask != null){
pendingResultTask
.addOnSuccessListener(onSuccess)
.addOnFailureListener(onFailure);
} else {
firebaseUser
.startActivityForLinkWithProvider(activity, provider.build())
.addOnSuccessListener(onSuccess)
.addOnFailureListener(onFailure);
}
}

/**
* signInWithPhoneNumber
*
Expand Down Expand Up @@ -1866,6 +1950,30 @@ private void promiseWithAuthResult(AuthResult authResult, Promise promise) {
WritableMap authResultMap = Arguments.createMap();
WritableMap userMap = firebaseUserToMap(authResult.getUser());

if(authResult.getCredential() != null){
if(authResult.getCredential() instanceof OAuthCredential){
OAuthCredential creds = (OAuthCredential) authResult.getCredential();
WritableMap credentialMap = Arguments.createMap();

credentialMap.putString("providerId", creds.getProvider());
credentialMap.putString("signInMethod", creds.getSignInMethod());

if(creds.getIdToken() != null){
credentialMap.putString("idToken", creds.getIdToken());
}

if(creds.getAccessToken() != null){
credentialMap.putString("accessToken", creds.getAccessToken());
}

if(creds.getSecret() != null){
credentialMap.putString("secret", creds.getSecret());
}

authResultMap.putMap("credential", credentialMap);
}
}

if (authResult.getAdditionalUserInfo() != null) {
WritableMap additionalUserInfoMap = Arguments.createMap();

Expand Down Expand Up @@ -1906,6 +2014,7 @@ private void promiseWithAuthResult(AuthResult authResult, Promise promise) {
*/
private void promiseRejectAuthException(Promise promise, Exception exception) {
WritableMap error = getJSError(exception);

final String sessionId = error.getString("sessionId");
final MultiFactorResolver multiFactorResolver = mCachedResolvers.get(sessionId);
WritableMap resolverAsMap = Arguments.createMap();
Expand All @@ -1927,6 +2036,8 @@ private WritableMap getJSError(Exception exception) {
String message = exception.getMessage();
String invalidEmail = "The email address is badly formatted.";

System.out.print(exception);

try {
FirebaseAuthException authException = (FirebaseAuthException) exception;
code = authException.getErrorCode();
Expand Down
22 changes: 10 additions & 12 deletions packages/auth/e2e/auth.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -912,12 +912,11 @@ describe('auth()', function () {
});

describe('signInWithPopup', function () {
it('should throw an unsupported error', function () {
(() => {
firebase.auth().signInWithPopup();
}).should.throw(
'firebase.auth().signInWithPopup() is unsupported by the native Firebase SDKs.',
);
it('should trigger the oauth flow', async function () {
await (async () => {
const provider = new firebase.auth.OAuthProvider('oidc.react.com');
await firebase.auth().signInWithPopup(provider);
}).should.not.throw();
});
});

Expand Down Expand Up @@ -1025,12 +1024,11 @@ describe('auth()', function () {
});

describe('signInWithRedirect()', function () {
it('should throw an unsupported error', function () {
(() => {
firebase.auth().signInWithRedirect();
}).should.throw(
'firebase.auth().signInWithRedirect() is unsupported by the native Firebase SDKs.',
);
it('should trigger the oauth flow', async function () {
await (async () => {
const provider = new firebase.auth.OAuthProvider('oidc.react.com');
await firebase.auth().signInWithRedirect(provider);
}).should.not.throw();
});
});

Expand Down
4 changes: 1 addition & 3 deletions packages/auth/e2e/provider.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,7 @@ describe('auth() -> Providers', function () {
describe('OAuthProvider', function () {
describe('constructor', function () {
it('should throw an unsupported error', function () {
(() => new firebase.auth.OAuthProvider()).should.throw(
'`new OAuthProvider()` is not supported on the native Firebase SDKs.',
);
(() => new firebase.auth.OAuthProvider('oidc.react.com')).should.not.throw();
});
});

Expand Down
116 changes: 115 additions & 1 deletion packages/auth/ios/RNFBAuth/RNFBAuthModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
static NSString *const keyHandleCodeInApp = @"handleCodeInApp";
static NSString *const keyDynamicLinkDomain = @"dynamicLinkDomain";
static NSString *const keyAdditionalUserInfo = @"additionalUserInfo";
static NSString *const keyCredential = @"credential";
static NSString *const keyIdToken = @"idToken";
static NSString *const keyAccessToken = @"accessToken";
static NSString *const keySecret = @"secret";
static NSString *const AUTH_STATE_CHANGED_EVENT = @"auth_state_changed";
static NSString *const AUTH_ID_TOKEN_CHANGED_EVENT = @"auth_id_token_changed";
static NSString *const PHONE_AUTH_STATE_CHANGED_EVENT = @"phone_auth_state_changed";
Expand All @@ -56,6 +60,7 @@
static __strong NSMutableDictionary<NSString *, FIRAuthCredential *> *credentials;
static __strong NSMutableDictionary<NSString *, FIRMultiFactorResolver *> *cachedResolver;
static __strong NSMutableDictionary<NSString *, FIRMultiFactorSession *> *cachedSessions;
static __strong NSMutableDictionary<NSString *, FIROAuthProvider *> *oAuthProviders;

@implementation RNFBAuthModule
#pragma mark -
Expand All @@ -77,6 +82,7 @@ - (id)init {
credentials = [[NSMutableDictionary alloc] init];
cachedResolver = [[NSMutableDictionary alloc] init];
cachedSessions = [[NSMutableDictionary alloc] init];
oAuthProviders = [[NSMutableDictionary alloc] init];
});
return self;
}
Expand Down Expand Up @@ -104,6 +110,7 @@ - (void)invalidate {
[credentials removeAllObjects];
[cachedResolver removeAllObjects];
[cachedSessions removeAllObjects];
[oAuthProviders removeAllObjects];
}

#pragma mark -
Expand Down Expand Up @@ -571,6 +578,73 @@ - (void)invalidate {
}];
}


RCT_EXPORT_METHOD(signInWithProvider
: (FIRApp *)firebaseApp
: (NSString *)providerID
: (NSString *_Nullable)email
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
FIROAuthProvider *provider = [FIROAuthProvider providerWithProviderID:providerID];
[oAuthProviders setValue:provider forKey:providerID];

if (email) {
[provider setCustomParameters:@{@"login_hint": email}];
}

[provider getCredentialWithUIDelegate:nil
completion:^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
}

if (credential) {
[[FIRAuth auth] signInWithCredential:credential
completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
}
else {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult credential:credential];
}
}];
}
}];
}

RCT_EXPORT_METHOD(linkWithProvider
: (FIRApp *)firebaseApp
: (NSString *)providerID
: (NSString *_Nullable)email
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
FIROAuthProvider *provider = [FIROAuthProvider providerWithProviderID:providerID];
[oAuthProviders setValue:provider forKey:providerID];

if (email) {
[provider setCustomParameters:@{@"login_hint": email}];
}

[provider getCredentialWithUIDelegate:nil
completion:^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
}

if (credential) {
[[FIRAuth auth].currentUser linkWithCredential:credential
completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
}
else {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult credential:credential];
}
}];
}
}];
}

RCT_EXPORT_METHOD(confirmPasswordReset
: (FIRApp *)firebaseApp
: (NSString *)code
Expand Down Expand Up @@ -1315,7 +1389,14 @@ - (void)promiseWithUser:(RCTPromiseResolveBlock)resolve

- (void)promiseWithAuthResult:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject
authResult:(FIRAuthDataResult *)authResult {
authResult:(FIRAuthDataResult *)authResult {
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult credential:nil];
}

- (void)promiseWithAuthResult:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject
authResult:(FIRAuthDataResult *)authResult
credential:(FIRAuthCredential *_Nullable)credential {
if (authResult && authResult.user) {
NSMutableDictionary *authResultDict = [NSMutableDictionary dictionary];

Expand Down Expand Up @@ -1347,6 +1428,39 @@ - (void)promiseWithAuthResult:(RCTPromiseResolveBlock)resolve
[authResultDict setValue:[NSNull null] forKey:keyAdditionalUserInfo];
}

if (credential && ([credential isKindOfClass:[FIROAuthCredential class]])) {
NSMutableDictionary *credentialDict = [NSMutableDictionary dictionary];
FIROAuthCredential* oAuthCredential = (FIROAuthCredential *)credential;

[credentialDict setValue:oAuthCredential.provider forKey:keyProviderId];

if (oAuthCredential.IDToken) {
[credentialDict setValue:oAuthCredential.IDToken forKey:keyIdToken];
}
else {
[credentialDict setValue:[NSNull null] forKey:keyIdToken];
}

if (oAuthCredential.accessToken) {
[credentialDict setValue:oAuthCredential.accessToken forKey:keyAccessToken];
}
else {
[credentialDict setValue:[NSNull null] forKey:keyAccessToken];
}

if (oAuthCredential.accessToken) {
[credentialDict setValue:oAuthCredential.secret forKey:keySecret];
}
else {
[credentialDict setValue:[NSNull null] forKey:keySecret];
}

[authResultDict setValue:credentialDict forKey:keyCredential];
}
else {
[authResultDict setValue:[NSNull null] forKey:keyCredential];
}

[authResultDict setValue:[self firebaseUserToDict:authResult.user] forKey:keyUser];
resolve(authResultDict);
} else {
Expand Down
14 changes: 6 additions & 8 deletions packages/auth/lib/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,14 @@ export default class User {
);
}

linkWithPopup() {
throw new Error(
'firebase.auth.User.linkWithPopup() is unsupported by the native Firebase SDKs.',
);
linkWithPopup(provider) {
return this._auth.native
.linkWithProvider(provider.providerId, provider.customParameters?.login_hint)
.then(userCredential => this._auth._setUserCredential(userCredential));
}

linkWithRedirect() {
throw new Error(
'firebase.auth.User.linkWithRedirect() is unsupported by the native Firebase SDKs.',
);
async linkWithRedirect(provider) {
return this.linkWithPopup(provider);
}

reauthenticateWithPhoneNumber() {
Expand Down
Loading

0 comments on commit 4a5a861

Please sign in to comment.