If you haven't already, follow the Getting Started steps in the main README.
In the Uber Developer Dashboard, under the Security section, enter your application's Bundle ID in the App Signatures
text field and tap the plus icon.
Next, add your application's Redirect URI to the list of URLs under Redirect URIs
. The preferred format is [Your App's Bundle ID]://oauth/consumer
, however any redirect URI may be used.
Once registered in the developer portal, add your redirect URI to your Xcode project's Info.plist
. This will allow the native Uber app to redirect back to your application upon successful authentication.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>[Your App's Bundle ID]</string>
<key>CFBundleURLSchemes</key>
<array>
<string>[Your App's Bundle ID]</string>
</array>
</dict>
</array>
<key>Uber</key>
<dict>
...
<key>RedirectURI</key>
<string>[Your Redirect URI]</string>
</dict>
To authenticate your app's user with Uber's backend, use the UberAuth API. In the simplest case, call the login method and respond to the result.
UberAuth.login { result: Result<Client, UberAuthError> in
// Handle result
}
Upon success, the result of the callback will contain a Client
object containing all credentials necessary to authenticate your user.
Property | Type | Description |
---|---|---|
authorizationCode | String? | The authorization code received from the authorization server. If this property is non-nil, all other properties will be nil. |
accessToken | String? | The access token issued by the authorization server. This property will only be populated if token exchange is enabled. |
refreshToken | String? | The type of the token issued. |
tokenType | String? | The type of the token issued. |
expiresIn | Int? | A token which can be used to obtain new access tokens. |
scope | [String]? | A comma separated list of scopes requested by the client. |
Upon failure, the result will contain an error of type UberAuthError. See Errors for more information.
For more complicated use cases, an auth context may be supplied to the login function. Use this type to specify additional customizations for the login experience:
- Auth Destination - Where the login should occur; in the native Uber app or inside your application.
- Auth Provider - The type of grant flow that should be used. Authorization Code Grant Flow is the only supported type.
- Prefill - Optional user information that should be prefilled when presenting the login screen.
let context = AuthContext(
authDestination: authDestination, // .native or .inApp
authProvider: authProvider, // .authorizationCode
prefill: prefill
)
UberAuth.login(
context: context,
completion: { result in
// Handle result
}
)
There are two locations or AuthDestination
s where authentication can be handled.
.inApp
- Presents the login screen inside the host application using a secure web browser via ASWebAuthenticationSession..native
- Links to the native Uber app, if installed. If not installed, falls back to .inApp. By default, native will attempt to open each of the following Uber apps in the following order: Uber Rides, Uber Eats, Uber Driver. If you would like to customize this order you can supply the order in the enum case's associated value. For example:.native([.eats, .driver, .rides])
will prefer the Uber Eats app first, and.native([.driver])
will only attempt to open the Uber Driver app and fall back to .inApp if unavailable.
let context = AuthContext(
authDestination: .native([.rides]) // Only launch the Uber Rides app, fallback to inApp
)
UberAuth.login(
context: context,
completion: { result in
// Handle result
}
)
In App | Native |
---|---|
An Auth Provider supplies logic for a specific authentication grant flow. Currently, the only supported auth provider is AuthorizationCoreAuthProvider
.
AuthorizationCoreAuthProvider performs the Authorization Code Grant Flow as specified in the OAuth 2.0 Framework. AuthorizationCoreAuthProvider is currently the only supported auth provider.
The auth provider accepts an optional prompt
parameter that can be used to force the login screen or the consent screen to be presented.
Note: Login is only available for .inApp auth destinations.
// Will request login then show the consent screen, even if previously completed by the user
let prompt: [Prompt] = [.login, .consent]
let authProvider: AuthProviding = .authorizationCode(
prompt: prompt
)
When using the native auth destination, your app will need to handle the callback deeplink in order to receive the users's credentials. There are multiple methods to handle this depending on your project setup.
Once handled, the original closure your supplied to the login method will be called, passing back a result with the Client object inside.
In your AppDelegate class, override the openUrl
method. Pass the incoming URL into the UberAuth.handle
method. If the URL is valid and UberAuth is able to parse it, it will return true and you can exit early from the openURL method.
import UberAuth
final class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// If handled == true, UberAuth was able to accept the url
if let handled = UberAuth.handle(url) {
return true
}
...
}
}
You may add an AppDelegate class to your SwiftUI app and use the method above. To do so, define an AppDelegate class in your main App entry point.
@main
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
...
}
Proceed with the steps above to handle incoming URLs in your AppDelegate.
SwiftUI View's provide a method for intercepting incoming URLs. In your SwiftUI view, use the onOpenURL handler to be notified when your app accepts an incoming deeplink.
struct ContentView: View {
var body: some View {
someView
.onOpenURL { url
let handled = UberAuth.handle(url)
}
}
}
In many cases, you may with to receive an access token and authorize a user inside your mobile app only, without the use of a backend service.
UberAuth supports this by allowing you to exchange the returned AuthorizationCode for an Access Token using PKCE. To do so, enable the flag shouldExchangeAuthCode
in the AuthorizationCodeAuthProvider context.
let authProvider: AuthProviding = .authorizationCode(
shouldExchangeAuthCode: true
)
UberAuth.login(
context: AuthContext(
authProvider: authProvider,
),
completion: { result in
// Handle result
}
)
Upon successful authentication, the Client object returned will contain a valid Access Token and Refresh Token.
Note: Authorization Code will be nil as it has been used for the token exchange and is no longer valid.
The SDK supports the OpenID login_hint
parameter for prefilling user information when authenticating with Uber.
To pass user information into the login page, ise the Prefill API when constructing the AuthContext. Partial information is accepted.
Note: Prefill information is only supported using the .inApp
login type.
Using UberAuth
let prefill = Prefill(
email: "[email protected]",
phoneNumber: "5555555555",
firstName: "Jane",
lastName: "Doe"
)
UberAuth.login(
context: AuthContext(
authDestination: .inApp,
authProvider: .authorizationCode(),
prefill: prefill
),
completion: { _ in }
)
Using the LoginButton / DataSource
final class MyLoginButtonDataSource: LoginButtonDataSource {
func authContext(_ button: LoginButton) -> AuthContext {
let prefill = Prefill(
email: "[email protected]",
phoneNumber: "5555555555",
firstName: "Jane",
lastName: "Doe"
)
return AuthContext(
authDestination: .inApp,
authProvider: .authorizationCode(),
prefill: prefill
)
}
}
As a convenience, the SDK provides a LoginButton
class that can be used to log a user in or out.
For simple cases, construct the button using the default initializer.
import UberAuth
let loginButton = LoginButton()
To receive the login result, conform to the LoginButtonDelegate
.
loginButton.delegate = MyLoginButtonDelegate()
...
final class MyLoginButtonDelegate: LoginButtonDelegate {
func loginButton(_ button: LoginButton, didLogoutWithSuccess success: Bool) {
// Successful logout
}
func loginButton(_ button: LoginButton, didCompleteLoginWithResult result: Result<Client, UberAuthError>) {
switch result {
case .success(let client):
// Handle Client response
break
case .failure(let error):
// Handle UberAuthError
break
}
}
}