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.
Option 2 — per link (?auth=required)
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:
| Method | What 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 →