Background
I am using the Lyft API to authenticate users with their 3 leg Oauth2 flow. I have added Deep Linking
to my app by following this documentation here.
When my app opens it immediately loads the Lyft Authentication page in Safari. After they go through the process to accept the permissions I have requested Safari tries to redirect to the URL I have set inside of my developer account at Lyft Developer
The problem here is I need the user to come back to my app with the response that Lyft gives when a user grants my application permissions.
What I have Tried
Deep Link
lyftauth://
I can type that link into Safari and it opens my app when I am on the phone, and if the app is installed. I tried to add that link as the redirect URL on the Lyft Developers page but it does not accept that url format.
So I know for sure I have to give the developers account page a URL to redirect, I know it will try to redirect to that URL and I know I cant use the correct URL to get my app to open back up.
React Native Oauth Libraries
I tried using the library react-native-oauth. When using this library I found that it does not work as expected. Many issues are opened on githu.com and a lot of them do not even have a response. I tried to for the library and edit the code to work for me but no matter what I ended up with a method being called on an object that did not exist. Specifically a method called authorize
.
Native Xcode Application
I built out a Xcode project using Swift and installing the Lyft SDK
with cocoapods. I was able to work with the API using this SDK. I was unable to incorporate React Native to the existing Swift project due to constant missing dependencies.
Code Examples
Using the docs for Linking mentioned above I added this code to my App Delegate file,
AppDelegate.m
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"Lyft"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
Then I went into the info.plist and added a link to open the app by,
I am importing Linking
to my React Native Component,
import React, { Component } from 'react';
import {
Linking,
} from 'react-native';
I added the code from the React Native Documentation to the React Native Component,
const url = 'https://api.lyft.com/oauth/authorize?client_id=PbUe5NjrXqQP&scope=public%20profile%20rides.read%20rides.request%20offline&state=true&response_type=code'
class App extends Component {
constructor(props) {
super(props);
this.state = {
}
this._handleOpenURL = this._handleOpenURL.bind(this);
}
componentDidMount() {
Linking.openURL(url);
Linking.addEventListener('url', this._handleOpenURL);
}
componentWillUnmount() {
Linking.removeEventListener('url', this._handleOpenURL);
}
_handleOpenURL(event) {
console.log(event.url);
console.log('WE ARE TRYING TO CALL THIS FUNCTION AT THIS POINT');
}
render() {
return (
...
);
}
}
export default App;
Question
What is the most common way to handle the Oauth2
redirect back to your application using React Native when the API
you are using does not specifically handle it for you?
Since this was a very hard problem to overcome and this question has not received a lot of attention, I suspect someone else in the future would appreciate an example of how I overcame this.
Problem
Handling the redirect after a user accepts permissions using the Lyft API 3 leg Oauth flow.
Solution
Example Solution Repo Here
In order to handle this I used Deep Linking which is supported by React Native. I also had to setup links in the IOS and Android applications. These links needed to be the same as the redirect URL in the Lyft Developers Page so the app could be opened back up when the link was fired off on the mobile device with the application on it. This can be done as followed,
Setup Deep Linking. Instructions on how to add Linking to your app can be found here.
The URLS are not explained at that React Native Link. Here are the resources for the Deep Links for each OS. Apple / Android
You will have to add a redirect URL to your Lyft App in the Developers page. This URL will be finessed into the native app settings for each OS, (IOS & ANDROID). You will make that the redirect URL in the Lyft Developer App Page here.
Code Example
Android
AndroidManifest.xml
<intent-filter android:label="lyft-app-authorize">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"
android:host="lyft-app"
android:pathPrefix="/authorize" />
</intent-filter>
<intent-filter android:label="lyft-app-authorize">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="lyft-app"
android:host="authorize" />
</intent-filter>
IOS
info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>lyft-app</string>
</array>
</dict>
</array>
AppDelegate.swift
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
Lyft Developer App Page
App Management Page
React Native
Load URL / Handle Redirect
componentDidMount() {
Linking.openURL(url);
Linking.addEventListener('url', (responseUrl) => {
console.log(responseUrl);
});
}