mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-27 21:01:03 +08:00
### Summary of Changes Previously, on the Swift SDK, the `signInWithOAuth` function wasn't working. In this PR, we fix it by having the `getOAuthUrl` function to actually redirect correctly. Note that to do so, we updated the `validRedirectUrl` check on the backend to accept app native redirects (from our new trusted url scheme). Another thing to note is that we added functionality to the `TokenStore` abstraction to conditionally refresh the access token that the user is trying to fetch if it is expired/close to expiring if possible. `getOAuthUrl` will attempt to get a valid access token, and thus will rely on our algorithm documented in `utilities.md`. The specs serve as the source of truth. We go further and implement Apple Native sign in. To do so, we have it hit a new route on the backend and verify the `jwtToken` retrieved by the sdk against an Apple-provided set of `jwks`. We use jose to do so, in line with the rest of the codebase. We take this opportunity to refactor the oauth provider route owing to the amount of duplicated logic. Additionally, to enable the apple sign in, users will have to update the Apple authentication method modal on the dashboard and add accepted bundle ids. These are identifiers for projects, and we will check the `JWT` on the backend to make sure the audience is set to an accepted bundleId. We also update the Apple modal to be more informative. ### Using the new Features To use the Apple native sign in, users will have to 1) sign up with an apple developer account, 2) set up their bundleids for their projects by connecting them to the apple developer account, 3) update the Stack-Auth Authentication Methods dashboard apple modal with the relevant fields. Then, trying to sign in with apple with our Swift SDK will use the apple native sign in. ### UI Changes Renamed the fields in the apple modal. Added a new field for bundle ids. See below. https://github.com/user-attachments/assets/0e760c0e-3198-4818-ac7f-4900d7a125bb Co-authored-by: Konstantin Wohlwend <n2d4xc@gmail.com>
196 lines
4.3 KiB
Markdown
196 lines
4.3 KiB
Markdown
# Stack Auth Swift SDK
|
|
|
|
Swift SDK for Stack Auth. Supports iOS, macOS, watchOS, tvOS, and visionOS.
|
|
|
|
## Requirements
|
|
|
|
- Swift 5.9+
|
|
- iOS 15+ / macOS 12+ / watchOS 8+ / tvOS 15+ / visionOS 1+
|
|
|
|
## Installation
|
|
|
|
Add to your `Package.swift`:
|
|
|
|
```swift
|
|
dependencies: [
|
|
.package(url: "https://github.com/stack-auth/swift-sdk-prerelease", from: <version>)
|
|
]
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```swift
|
|
import StackAuth
|
|
|
|
let stack = StackClientApp(
|
|
projectId: "your-project-id",
|
|
publishableClientKey: "your-key"
|
|
)
|
|
|
|
// Sign in with email/password
|
|
try await stack.signInWithCredential(email: "user@example.com", password: "password")
|
|
|
|
// Get current user
|
|
if let user = try await stack.getUser() {
|
|
print("Signed in as \(user.displayName ?? "Unknown")")
|
|
}
|
|
|
|
// Sign out
|
|
try await stack.signOut()
|
|
```
|
|
|
|
## Design Decisions
|
|
|
|
### Error Handling
|
|
|
|
All functions that can fail use Swift's native `throws`. Errors conform to `StackAuthError`:
|
|
|
|
```swift
|
|
do {
|
|
try await stack.signInWithCredential(email: email, password: password)
|
|
} catch let error as StackAuthError {
|
|
switch error.code {
|
|
case "email_password_mismatch":
|
|
print("Wrong password")
|
|
default:
|
|
print(error.message)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Token Storage
|
|
|
|
- **Default**: Keychain (secure, persists across app launches)
|
|
- **Option**: Memory (for testing or ephemeral sessions)
|
|
- **Option**: Custom `TokenStoreProtocol` implementation
|
|
|
|
```swift
|
|
// Memory storage (for testing)
|
|
let stack = StackClientApp(
|
|
projectId: "...",
|
|
publishableClientKey: "...",
|
|
tokenStore: .memory
|
|
)
|
|
|
|
// Custom storage
|
|
let stack = StackClientApp(
|
|
projectId: "...",
|
|
publishableClientKey: "...",
|
|
tokenStore: .custom(MyTokenStore())
|
|
)
|
|
```
|
|
|
|
### OAuth Flows
|
|
|
|
Two approaches for OAuth authentication:
|
|
|
|
**1. Integrated (recommended)** - Uses `ASWebAuthenticationSession`:
|
|
|
|
```swift
|
|
// Opens auth session, handles callback automatically
|
|
// Uses fixed callback scheme: stack-auth-mobile-oauth-url://
|
|
try await stack.signInWithOAuth(provider: "google")
|
|
```
|
|
|
|
**2. Manual URL handling** - For custom implementations:
|
|
|
|
> **Note:** The `stack-auth-mobile-oauth-url://` scheme is automatically accepted.
|
|
|
|
```swift
|
|
// Get the OAuth URL (must provide absolute URLs)
|
|
let oauth = try await stack.getOAuthUrl(
|
|
provider: "google",
|
|
redirectUrl: "stack-auth-mobile-oauth-url://success",
|
|
errorRedirectUrl: "stack-auth-mobile-oauth-url://error"
|
|
)
|
|
|
|
// Open oauth.url in your own browser/webview
|
|
// Store oauth.state, oauth.codeVerifier, and oauth.redirectUrl
|
|
|
|
// When callback received:
|
|
try await stack.callOAuthCallback(
|
|
url: callbackUrl,
|
|
codeVerifier: oauth.codeVerifier,
|
|
redirectUrl: oauth.redirectUrl
|
|
)
|
|
```
|
|
|
|
### Async/Await
|
|
|
|
All async operations use Swift's native concurrency:
|
|
|
|
```swift
|
|
Task {
|
|
let user = try await stack.getUser()
|
|
let teams = try await user?.listTeams()
|
|
}
|
|
```
|
|
|
|
## Key Differences from JavaScript SDK
|
|
|
|
| Aspect | JavaScript | Swift |
|
|
|--------|-----------|-------|
|
|
| Token Storage | Cookies | Keychain |
|
|
| OAuth | Browser redirect | ASWebAuthenticationSession |
|
|
| Redirect methods | Available | Not available (browser-only) |
|
|
| React hooks | `useUser()` etc. | Not applicable |
|
|
|
|
### Not Available in Swift
|
|
|
|
The following are browser-only and not exposed:
|
|
|
|
- `redirectToSignIn()`, `redirectToSignUp()`, etc.
|
|
- Cookie-based token storage
|
|
- `redirectMethod` constructor option
|
|
|
|
## Examples
|
|
|
|
Interactive example apps are available for testing all SDK functions:
|
|
|
|
### macOS Example
|
|
|
|
```bash
|
|
cd Examples/StackAuthMacOS
|
|
swift run
|
|
```
|
|
|
|
Features a sidebar-based UI for testing authentication, user management, teams, OAuth, tokens, and server-side operations.
|
|
|
|
### iOS Example
|
|
|
|
```bash
|
|
cd Examples/StackAuthiOS
|
|
open Package.swift # Opens in Xcode
|
|
```
|
|
|
|
Features a tab-based UI optimized for iOS with the same comprehensive SDK coverage.
|
|
|
|
Both examples include:
|
|
- Configurable API endpoints
|
|
- Real-time operation logs
|
|
- Error testing scenarios (wrong password, unauthorized access, etc.)
|
|
- Client and server app operations
|
|
|
|
## Testing
|
|
|
|
Tests use Swift Testing framework against a running backend.
|
|
|
|
### Running Tests
|
|
|
|
1. Start the development server:
|
|
```bash
|
|
pnpm dev
|
|
```
|
|
|
|
2. Run tests:
|
|
```bash
|
|
cd sdks/implementations/swift
|
|
swift test
|
|
```
|
|
|
|
The tests connect to `http://localhost:8102` (or `${NEXT_PUBLIC_STACK_PORT_PREFIX}02`).
|
|
|
|
## API Reference
|
|
|
|
See the [SDK Specification](../../spec/README.md) for complete API documentation.
|