| 1 | # Quick Start — iOS |
| 2 | |
| 3 | This guide shows the hosted smbCloud Auth flow for an iPhone or iPad app using `SmbCloudWebAuth` and `SmbCloudCredentialsManager`. |
| 4 | |
| 5 | ## 1. Add the package |
| 6 | |
| 7 | Add `https://github.com/smbcloudXYZ/smbcloud-auth-swift` in Xcode or Swift Package Manager. |
| 8 | |
| 9 | ## 2. Register a callback URL scheme |
| 10 | |
| 11 | Your app needs a callback URL such as: |
| 12 | |
| 13 | - `myapp://auth/callback` |
| 14 | |
| 15 | Add the URL scheme in your app target settings so iOS can route the hosted auth callback back into the app. |
| 16 | |
| 17 | ## 3. Create a small auth store |
| 18 | |
| 19 | Use one public client ID from smbCloud Auth. |
| 20 | Do not embed an `app_secret` in the app. |
| 21 | |
| 22 | ```swift |
| 23 | import SmbCloudAuth |
| 24 | import SwiftUI |
| 25 | |
| 26 | @MainActor |
| 27 | final class AuthenticationStore: ObservableObject { |
| 28 | @Published private(set) var session: SmbCloudSession? |
| 29 | @Published private(set) var email: String? |
| 30 | @Published private(set) var errorMessage: String? |
| 31 | @Published private(set) var isLoading = false |
| 32 | |
| 33 | private let webAuth = SmbCloudWebAuth( |
| 34 | environment: .production, |
| 35 | oidcClientId: "YOUR_OIDC_CLIENT_ID", |
| 36 | redirectURL: URL(string: "myapp://auth/callback")! |
| 37 | ) |
| 38 | private let credentialsManager = SmbCloudCredentialsManager( |
| 39 | service: "com.example.myapp.smbcloud-auth" |
| 40 | ) |
| 41 | |
| 42 | func restoreSession() { |
| 43 | do { |
| 44 | session = try credentialsManager.currentValidSession() |
| 45 | } catch { |
| 46 | errorMessage = error.localizedDescription |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | func signIn(anchor: @escaping () -> SmbCloudPresentationAnchor) async { |
| 51 | isLoading = true |
| 52 | errorMessage = nil |
| 53 | defer { isLoading = false } |
| 54 | |
| 55 | do { |
| 56 | let session = try await webAuth.login( |
| 57 | presentationAnchorProvider: anchor, |
| 58 | credentialsManager: credentialsManager |
| 59 | ) |
| 60 | self.session = session |
| 61 | |
| 62 | let user = try await webAuth.userInfo(session: session) |
| 63 | email = user.email |
| 64 | } catch { |
| 65 | errorMessage = error.localizedDescription |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | func signOut() { |
| 70 | do { |
| 71 | try webAuth.clearSession(credentialsManager: credentialsManager) |
| 72 | session = nil |
| 73 | email = nil |
| 74 | errorMessage = nil |
| 75 | } catch { |
| 76 | errorMessage = error.localizedDescription |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | ``` |
| 81 | |
| 82 | ## 4. Provide a presentation anchor |
| 83 | |
| 84 | For SwiftUI on iOS, the simplest approach is to return the current key window. |
| 85 | |
| 86 | ```swift |
| 87 | import UIKit |
| 88 | |
| 89 | func currentPresentationAnchor() -> UIWindow { |
| 90 | UIApplication.shared.connectedScenes |
| 91 | .compactMap { $0 as? UIWindowScene } |
| 92 | .flatMap(\.windows) |
| 93 | .first { $0.isKeyWindow } ?? UIWindow() |
| 94 | } |
| 95 | ``` |
| 96 | |
| 97 | ## 5. Build a simple screen |
| 98 | |
| 99 | ```swift |
| 100 | import SwiftUI |
| 101 | |
| 102 | struct ContentView: View { |
| 103 | @StateObject private var authStore = AuthenticationStore() |
| 104 | |
| 105 | var body: some View { |
| 106 | VStack(spacing: 16) { |
| 107 | if let email = authStore.email { |
| 108 | Text("Signed in as \(email)") |
| 109 | } else if authStore.session != nil { |
| 110 | Text("Signed in") |
| 111 | } else { |
| 112 | Text("Signed out") |
| 113 | } |
| 114 | |
| 115 | if authStore.session != nil { |
| 116 | Button("Sign Out") { |
| 117 | authStore.signOut() |
| 118 | } |
| 119 | } else { |
| 120 | Button("Continue with smbCloud") { |
| 121 | Task { |
| 122 | await authStore.signIn { |
| 123 | currentPresentationAnchor() |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | if let errorMessage = authStore.errorMessage { |
| 130 | Text(errorMessage) |
| 131 | .foregroundStyle(.red) |
| 132 | .multilineTextAlignment(.center) |
| 133 | } |
| 134 | } |
| 135 | .padding() |
| 136 | .task { |
| 137 | authStore.restoreSession() |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | ``` |
| 142 | |
| 143 | ## 6. What happens during login |
| 144 | |
| 145 | 1. `SmbCloudWebAuth` creates a PKCE authorization request. |
| 146 | 2. `ASWebAuthenticationSession` opens the hosted smbCloud login page. |
| 147 | 3. smbCloud Auth redirects to your app callback URL. |
| 148 | 4. The SDK validates `state`, exchanges the authorization code, and returns `SmbCloudSession`. |
| 149 | 5. `SmbCloudCredentialsManager` stores the session in Keychain. |
| 150 | |
| 151 | ## Notes |
| 152 | |
| 153 | - Prefer an explicit Keychain `service` value per app. |
| 154 | - Do not show or log raw access tokens in production UI. |
| 155 | - `logout()` currently clears local stored credentials. It does not revoke tokens remotely. |
| 156 | - Hosted web login requires `ASWebAuthenticationSession`, so use iOS 16+. |
| 157 | - If your product needs native email/password forms, send those credentials to your backend or BFF instead of embedding confidential credentials in the app. |
| 158 | |
| 159 | ## Related docs |
| 160 | |
| 161 | - `Docs/QuickStart-macOS.md` |
| 162 | - `Docs/Migration-From-Proxy-Native-Forms.md` |