Skip to content

Add support for Facebook Limited Login. #995

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

Merged
merged 8 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 80 additions & 25 deletions FirebaseFacebookAuthUI/Sources/FUIFacebookAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ @interface FUIFacebookAuth () <FUIAuthProvider>
*/
@property(nonatomic, strong) FIROAuthProvider *providerForEmulator;

/** @property currentNonce
@brief The nonce for the current Facebook Limited Login session, if any.
*/
@property(nonatomic, copy, nullable) NSString *currentNonce;

@end

@implementation FUIFacebookAuth {
Expand Down Expand Up @@ -131,6 +136,9 @@ - (nullable NSString *)providerID {
return FIRFacebookAuthProviderID;
}

/** @fn accessToken:
@brief The access token provided by Facebook's login flow.
*/
- (nullable NSString *)accessToken {
if (self.authUI.isEmulatorEnabled) {
return nil;
Expand All @@ -139,10 +147,13 @@ - (nullable NSString *)accessToken {
}

/** @fn idToken:
@brief Facebook doesn't provide User Id Token during sign in flow
@brief The ID token provided by Facebook's login flow.
*/
- (nullable NSString *)idToken {
return nil;
if (self.authUI.isEmulatorEnabled) {
return nil;
}
return FBSDKAuthenticationToken.currentAuthenticationToken.tokenString;
}

- (NSString *)shortName {
Expand Down Expand Up @@ -191,29 +202,45 @@ - (void)signInWithDefaultValue:(nullable NSString *)defaultValue
return;
}

[_loginManager logInWithPermissions:_scopes
fromViewController:presentingViewController
handler:^(FBSDKLoginManagerLoginResult *result,
NSError *error) {
if (error) {
NSError *newError =
[FUIAuthErrorUtils providerErrorWithUnderlyingError:error
providerID:FIRFacebookAuthProviderID];
[self completeSignInFlowWithAccessToken:nil error:newError];
} else if (result.isCancelled) {
NSError *newError = [FUIAuthErrorUtils userCancelledSignInError];
[self completeSignInFlowWithAccessToken:nil error:newError];
} else {
if (self.useLimitedLogin) {
// Facebook Limited Login
NSString *nonce = [FUIAuthUtils randomNonce];
self.currentNonce = nonce;
FBSDKLoginConfiguration *configuration =
[[FBSDKLoginConfiguration alloc] initWithPermissions:_scopes
tracking:FBSDKLoginTrackingLimited
nonce:[FUIAuthUtils stringBySHA256HashingString:nonce]];
[_loginManager logInFromViewController:presentingViewController
configuration:configuration
completion:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if ([self maybeHandleCancelledResult:result error:error]) {
return;
}
self->_email = FBSDKProfile.currentProfile.email;
NSString *idToken = FBSDKAuthenticationToken.currentAuthenticationToken.tokenString;
[self completeSignInFlowWithAccessToken:nil idToken:idToken error:nil];
}];
} else {
[_loginManager logInWithPermissions:_scopes
fromViewController:presentingViewController
handler:^(FBSDKLoginManagerLoginResult *result,
NSError *error) {
if ([self maybeHandleCancelledResult:result error:error]) {
return;
}
// Retrieve email.
[[[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{ @"fields" : @"email" }] startWithCompletion:^(id<FBSDKGraphRequestConnecting> connection,
id result,
NSError *error) {
[[[FBSDKGraphRequest alloc] initWithGraphPath:@"me"
parameters:@{ @"fields" : @"email" }]
startWithCompletion:^(id<FBSDKGraphRequestConnecting> connection,
id result,
NSError *error) {
self->_email = result[@"email"];
}];
[self completeSignInFlowWithAccessToken:result.token.tokenString
idToken:nil
error:nil];
}
}];
}];
}
}

- (void)signInWithOAuthProvider:(FIROAuthProvider *)oauthProvider
Expand Down Expand Up @@ -269,21 +296,31 @@ - (BOOL)handleOpenURL:(NSURL *)URL sourceApplication:(NSString *)sourceApplicati

#pragma mark -

/** @fn completeSignInFlowWithAccessToken:error:
/** @fn completeSignInFlowWithAccessToken:idToken:error:
@brief Called with the result of a Facebook sign-in attempt. Invokes and clears any pending
sign in callback block.
@param accessToken The Facebook access token, if successful.
@param accessToken The Facebook access token, if the Facebook sign-in attempt with tracking enabled is successful.
@param idToken The Facebook ID token, if the Facebook Limited Login attempt is successful.
@param error An error which occurred during the sign-in attempt.
*/
- (void)completeSignInFlowWithAccessToken:(nullable NSString *)accessToken
idToken:(nullable NSString *)idToken
error:(nullable NSError *)error {
if (error) {
[self callbackWithCredential:nil error:error result:nil];
return;
}
// Assume accessToken cannot be nil if there's no error.
NSString *_Nonnull token = (id _Nonnull)accessToken;
FIRAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:token];
FIRAuthCredential *credential;
if (idToken) {
NSString *rawNonce = self.currentNonce;
credential = [FIROAuthProvider credentialWithProviderID:FIRFacebookAuthProviderID
IDToken:idToken
rawNonce:rawNonce];
} else {
// Assume accessToken cannot be nil if there's no error and idToken is nil.
NSString *_Nonnull token = (id _Nonnull)accessToken;
credential = [FIRFacebookAuthProvider credentialWithAccessToken:token];
}
UIActivityIndicatorView *activityView =
[FUIAuthBaseViewController addActivityIndicator:_presentingViewController.view];
[activityView startAnimating];
Expand Down Expand Up @@ -347,4 +384,22 @@ - (FBSDKLoginManager *)createLoginManager {
return [[FBSDKLoginManager alloc] init];
}

- (BOOL)maybeHandleCancelledResult:(FBSDKLoginManagerLoginResult *)result
error:(NSError *)error {
if (error) {
NSError *newError =
[FUIAuthErrorUtils providerErrorWithUnderlyingError:error
providerID:FIRFacebookAuthProviderID];
[self completeSignInFlowWithAccessToken:nil idToken:nil error:newError];
return true;
}

if (result.isCancelled) {
NSError *newError = [FUIAuthErrorUtils userCancelledSignInError];
[self completeSignInFlowWithAccessToken:nil idToken:nil error:newError];
return true;
}
return false;
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property(nonatomic, readwrite) FUIButtonAlignment buttonAlignment;

/** @property useLimitedLogin
@brief Whether or not Facebook Login should use Limited Login mode.
*/
@property(nonatomic, assign) BOOL useLimitedLogin;

/** @fn initWithAuthUI
@brief Convenience initializer. Uses a default permission of `@[ "email" ]`.
@param authUI The @c FUIAuth instance that manages this provider.
Expand Down
3 changes: 3 additions & 0 deletions FirebaseOAuthUI/Sources/FUIOAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ @interface FUIOAuth () <ASAuthorizationControllerDelegate, ASAuthorizationContro
*/
@property(nonatomic, copy, nullable) NSString *loginHintKey;

/** @property currentNonce
@brief The nonce for the current Sign in with Apple session, if any.
*/
@property(nonatomic, copy, nullable) NSString *currentNonce;

/** @property provider
Expand Down
6 changes: 6 additions & 0 deletions samples/objc/FirebaseUI-demo-objc/FUIAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

@import Firebase;
@import FirebaseAuthUI;
@import FBSDKCoreKit;
#import <GTMSessionFetcher/GTMSessionFetcherLogging.h>

@implementation FUIAppDelegate
Expand All @@ -26,13 +27,18 @@ - (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[FIRApp configure];
[GTMSessionFetcher setLoggingEnabled:YES];
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
return YES;
}

- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<NSString*, id> *)options {
NSString *sourceApplication = options[UIApplicationOpenURLOptionsSourceApplicationKey];
[[FBSDKApplicationDelegate sharedInstance] application:app
openURL:url
options:options];
return [self handleOpenUrl:url sourceApplication:sourceApplication];
}

Expand Down
31 changes: 24 additions & 7 deletions samples/objc/FirebaseUI-demo-objc/Resources/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="7RW-VL-qNI">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="7RW-VL-qNI">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
Expand Down Expand Up @@ -162,7 +162,7 @@
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Custom Authorization UI" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="YxK-c8-9q7">
<rect key="frame" x="27" y="12" width="322" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<color key="textColor" systemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="JZd-6c-Soe">
Expand Down Expand Up @@ -191,7 +191,7 @@
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Custom Scopes" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="T07-wL-pGr">
<rect key="frame" x="27" y="12" width="322" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<color key="textColor" systemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="9Ma-Mx-g56">
Expand Down Expand Up @@ -225,14 +225,14 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" alpha="0.80000000000000004" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Link" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ig5-8M-jHk">
<label opaque="NO" userInteractionEnabled="NO" alpha="0.80000000000000004" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Link" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ig5-8M-jHk">
<rect key="frame" x="244" y="10.5" width="48" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LiB-gr-jDR">
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LiB-gr-jDR">
<rect key="frame" x="300" y="5.5" width="49" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<connections>
Expand Down Expand Up @@ -273,6 +273,17 @@
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" alpha="0.80000000000000004" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Limited" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XLV-Sd-fV6">
<rect key="frame" x="244" y="11.5" width="48" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="H4b-GH-bc7" userLabel="Facebook Switch">
<rect key="frame" x="300" y="6.5" width="49" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</switch>
</subviews>
</tableViewCellContentView>
</tableViewCell>
Expand Down Expand Up @@ -537,6 +548,7 @@
<outlet property="customScopeSwitch" destination="9Ma-Mx-g56" id="Scy-Do-CrR"/>
<outlet property="emailLabel" destination="ig5-8M-jHk" id="a2T-8z-dxJ"/>
<outlet property="emailSwitch" destination="LiB-gr-jDR" id="I2g-oL-ZRC"/>
<outlet property="facebookSwitch" destination="H4b-GH-bc7" id="z4w-iM-AYz"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="1w1-3x-wCC" userLabel="First Responder" sceneMemberID="firstResponder"/>
Expand All @@ -561,7 +573,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jIg-6e-k6g">
<rect key="frame" x="0.0" y="617" width="375" height="50"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="T3i-kj-emg">
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="T3i-kj-emg">
<rect key="frame" x="333" y="8" width="34" height="34"/>
<state key="normal" title="Load"/>
<connections>
Expand Down Expand Up @@ -608,4 +620,9 @@
<point key="canvasLocation" x="2377" y="315"/>
</scene>
</scenes>
<resources>
<systemColor name="darkTextColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
Loading