iOS
Rownd bindings for native iOS apps
Rownd SDK for iOS
The Rownd SDK for iOS provides authentication, account and user profile management, deep linking, and more for native iPhone, iPad, and even macOS applications.
Using the Rownd platform, you can easily bring the same authentication that’s on your website to your mobile apps. Or if you only authenticate users on your mobile apps, you can streamline the authentication process using Rownd’s passwordless sign-in links, enabling you to seamlessly authenticate users from an app link sent to their email or phone number.
Once a user is authenticated, you can retrieve and update their profile information on the fly using native APIs. Leverage Rownd’s pre-built mobile app components to give users profile management tools.
Installation
In Xcode, select your project file, select the main target, then scroll down to the “frameworks” section to add a package dependency to your project. See the official documentation for specific steps.
Enter this as the package repository url:
Usage
Initializing the Rownd SDK
In your AppDelegate
file, call the Rownd.configure()
method during application launch:
After initialization, your app will typically call Rownd.requestSignIn()
at some point, if the user is not already authenticated. This will display the Rownd interface for authenticating the user. Once they complete the sign-in process, an access token and the user’s profile information will be available to your app.
Handling authentication
Rownd leverages an observeable architecture to expose data to your app. This means that as the Rownd state changes, an app can dynamically update without complicated logic. For example, a view can display different information based on the user’s authentication status.
Here’s an example SwiftUI view that displays different messages depending on the user’s authenticated status:
Example usage outside of SwiftUI
You can subscribe to any state object that Rownd supports. Here’s a list of available states and their structures:
.auth
.user
Getting an access token
Whenever your app needs to make an authenticated request to your backend, you’ll need to get an access token. You can do this by calling await Rownd.getAccessToken()
. If the user is not authenticated, this function will return nil
.
If there is an issue fetching the access token (e.g., during a token refresh), an error will be thrown. Network failures are currently not retried (though this behavior may change in the future). Currently, we suggest retrying once in the event of an error and otherwise notifying the user to try again later, check their connection, etc.
See the API reference for more information.
Customizing the UI
While most customizations are handled via the Rownd dashboard, there are a few things that have to be customized directly in the SDK.
The RowndCustomizations
class exists to facilitate these customizations. It provides the following properties that may be subclassed or overridden.
sheetBackgroundColor: UIColor
(default:light: .white
,dark: .systemGray6
; requires subclassing) - Allows changing the background color underlaying the bottom sheet that appears when signing in, managing the user account, etc.sheetCornerBorderRadius: CGFloat
(default:25.0
) - Modifies the curvature radius of the bottom sheet corners.loadingAnimation: Lottie.Animation
(default: nil) - Replace Rownd’s use of the system default loading spinner (i.e.,UIActivityIndicatorView
orProgressView
) with a custom animation. Any animation compatible with Lottie should work, but will be scaled to fit a 1:1 aspect ratio (usually with aCGRect
frame width/height of100
)
To apply customizations, we recommend subclassing the RowndCustomizations
class. Here’s an example:
Usage within app extensions
It’s possible to access the Rownd state from within an app extension, like a widget. You’ll need to include the Rownd package in the extension’s dependencies and set up an app group for data sharing between the app and the extension. Without the app group, extensions will not be able to sync with your app’s authentication state.
Follow these steps to configure your app and extension to work with Rownd:
-
Add an app group entitlement to both your app and any extensions that will use Rownd. This app group must be named like this:
<prefix>.io.rownd.sdk
. For example, if you work at a company with the acme.com domain, your app group might look like this:com.acme.app.io.rownd.sdk
. Rownd will store its data in this app group. Your app should store data in a separate app group to prevent any collisions. -
In your app’s
AppDelegate
file as well as your extension’s entry point, set the app group prefix you defined above viaRownd.config.appGroupPrefix = "<prefix>"
(e.g.,Rownd.config.appGroupPrefix = "com.acme.app"
) -
In your extension, call
Rownd.configure()
prior to accessing authentication state. Here’s an example:
If you’re building widgets that need access to Rownd auth state, you should listen for Rownd auth events and notify WidgetCenter
that widgets may need updating any time the state changes. That way, they’ll re-render while your app is in the foreground and will show an accurate state. Here’s a simple example:
Events
The Rownd SDK emits lifecycle events that you can listen to within your app. These events are primarily useful for detecting more granular aspects of a user’s session (e.g., starting to sign in, completing sign-in, updated profile, etc.).
To listen to events, first create a class that conforms to the RowndEventHandlerDelegate
protocol. It looks something like this:
Next, register the event handler delegate with the Rownd SDK:
Once the event handler is registered, it will receive events as they occur. The RowndEvent
object contains the event type and any associated data. The event types are defined in the RowndEventType
enum.
List of events
Here’s a list of events that the Rownd SDK emits and the corresponding data that should be present in the event data dictionary. Remember to write your code defensively, as the data dictionary may be missing keys in some cases.
Event | Type | Payload |
---|---|---|
User started signing in | .signInStarted | |
User signed in successfully | .signInCompleted | |
User sign in failed | .signInFailed |
API reference
In addition to the state observable APIs, Rownd provides imperative APIs that you can call to request sign in, get and retrieve user profile information, retrieve a current access token, or encrypt user data with the user’s local key.
Rownd.requestSignIn() -> Void
Opens the Rownd sign-in dialog for authentication.
Rownd.requestSignIn(RowndSignInOptions(postSignInRedirect: “https://my-domain.com”)) -> Void
Rownd.requestSignIn(RowndSignInOptions(postSignInRedirect: “https://my-domain.com”, intent: .signIn)) -> Void
Opens the Rownd sign-in dialog for authentication, as above. When the user completes the authentication challenge via email or SMS, they’ll be redirected to the URL set for postSignInRedirect
. If this is a Universal Link, it will redirect the user back to your app.
Rownd.requestSignIn(with: RowndSignInHint) -> Void
Rownd.requestSignIn(with: RowndSignInHint, signInOptions: RowndSignInOptions?) -> Void
Requests a sign-in, but with a specific authentication provider (e.g., Sign in with Apple). Rownd treats this information as a hint. If the specified authentication provider is enabled within your Rownd app configuration, it will be honored. If not, Rownd will fall back to the default flow.
Supported values:
.appleId
- Prompt user to sign in with their Apple ID.google
- Prompt user to sign in with their Google account.passkey
- Prompt user to sign in with a passkey if they’ve previously set one up.guest
- Sign in the user anonymously as a guest.
RowndSignInOptions
Some of the requestSignIn()
methods accept an optional RowndSignInOptions
parameter. This class contains the following properties:
postSignInRedirect: String?
(not recommended) - When the user completes the authentication challenge via email or SMS, they’ll be redirected to the URL set forpostSignInRedirect
. If this is a Universal Link, it will redirect the user back to your app. If you don’t set this value, the user will be redirected to your app’s subdomain as configured in the Rownd dashboard.intent: RowndSignInIntent?
- This option applies only when you have opted to split the sign-up/sign-in flow via the Rownd dashboard. Valid values are.signIn
or.signUp
. If you don’t set this value, the user will be presented with the unified sign-in/sign-up flow.
Rownd.getAccessToken() async throws -> String?
Assuming a user is signed-in, returns a valid access token, refreshing the current one if needed.
If an access token cannot be returned due to a temporary condition (e.g., inaccessible network), this function will throw
.
If an access token cannot be returned because the refresh token is invalid, nil
will be returned and the Rownd state
will sign out the user.
Example:
Rownd.getAccessToken(_ token: String) async -> String?
When possible, exchanges a non-Rownd access token for a Rownd access token. This is primarily used in scenarios where an app is migrating from some other authentication mechanism to Rownd. Using Rownd integrations, the system will accept a third-party token. If it successfully validates, Rownd will sign-in the user and return a fresh Rownd access token to the caller.
This API returns nil
if the token could not be validated and exchanged. If that occurs, it’s likely
that the user should sign-in normally via Rownd.requestSignIn()
.
NOTE: This API is typically used once. After a Rownd token is available, other tokens should be discarded. Example:
Rownd.user.get() -> Dictionary<String, AnyCodable>
Returns the entire user profile as a dictionary object
Rownd.user.get<T>(field: String) -> T?
Returns the value of a specific field in the user’s data dictionary. "id"
is a special case that will return the user’s ID, even though it’s technically not in the dictionary itself.
Your application code is responsible for knowing which type the value should cast to. If the cast fails or the entry doesn’t exist, a nil
value will be returned.
Rownd.user.set(data: Dictionary<String, AnyCodable>) -> void
Replaces the user’s data with that contained in the dictionary. This may overwrite existing values, but must match the schema you defined within your Rownd application dashboard. Any fields that are flagged as encrypted
will be encrypted on-device prior to storing in Rownd’s platform.
Hint: use AnyCodable.init(value)
to conform your values to the required type.
Rownd.user.set(field: String, value: AnyCodable) -> void
Sets a specific user profile field to the provided value, overwriting if a value already exists. If the field is flagged as encrypted
, it will be encrypted on-device prior to storing in Rownd’s platform.
Hint: use AnyCodable.init(value)
to conform your values to the required type.