Skip to main content

Module 6 — Auth-gated destinations

Some screens should only open for a logged-in user (a wallet, an account page, an "apply" form). A link is treated as auth-gated when either of these is true:

requiresAuth = (destination is in authRequiredDestinations)  OR  (link carries ?auth=required)

Option 1 — by destination (config)

List the always-protected destinations once, in SDK setup:

deepLinkConfig.authRequiredDestinations = ["wallet", "account"]

Every link to wallet / account is then gated, regardless of how it was built.

A single link can opt in without any config change — useful when a campaign wants one specific link (e.g. an "apply" or "checkout" link) to require login:

yourapp://campaigns/summer/apply?auth=required

Handle the gate

In both cases the SDK invokes your auth handler instead of navigating immediately:

PaylisherSDK.shared.onDeepLinkRequiresAuth { deepLink, complete in
if isUserLoggedIn {
complete(true) // already authenticated → proceed
} else {
presentLogin { success in
complete(success) // after login, the SDK resumes to the destination
}
}
}

After complete(true), the SDK finishes the pending link and calls your onDeepLink handler with requiresAuth == false — so the actual navigation still flows through your router.

The cold-start case

The hard case is a link to a protected screen tapped while the app is killed and logged out. The robust pattern: store the pending completion, show your login screen, and fire the completion once login succeeds.

final class DeepLinkRouter: ObservableObject {
@Published var isAuthenticated = false
private var pendingAuthCompletion: ((Bool) -> Void)?

func handleAuthRequired(_ deepLink: PaylisherDeepLink, completion: @escaping (Bool) -> Void) {
DispatchQueue.main.async {
if self.isAuthenticated {
completion(true) // already logged in → straight through
} else {
self.pendingAuthCompletion = completion // logged out → wait for login
}
}
}

/// Call from your login/logout flow.
func setAuthenticated(_ value: Bool) {
isAuthenticated = value
if value, let completion = pendingAuthCompletion {
pendingAuthCompletion = nil
completion(true) // resumes the waiting deep link
}
}
}

Wire it in SDK setup:

PaylisherSDK.shared.onDeepLinkRequiresAuth { deepLink, complete in
DeepLinkRouter.shared.handleAuthRequired(deepLink, completion: complete)
}

And call setAuthenticated(true) on login success, setAuthenticated(false) on logout.


Manual control

You can also drive the gate yourself instead of using the completion handler:

MethodWhat it does
completePendingDeepLink()Completes a pending auth-gated link after successful login.
cancelPendingDeepLink()Cancels a pending link (emits a Deep Link Cancelled event).

A pending link expires after pendingDeepLinkTimeout (default 5 minutes), emitting a Deep Link Timeout event.

Next: Module 7 — Deferred deep links