Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
227 commits
Select commit Hold shift + click to select a range
a8d532e
initial theme and localization setup
mikepitre Apr 9, 2025
a134ba2
add font customization
mikepitre Apr 10, 2025
97de905
allow wider code in formatter
mikepitre Apr 10, 2025
ac857eb
replace caption1 with caption
mikepitre Apr 10, 2025
c900d9f
add clerk colors and generated colors
mikepitre Apr 10, 2025
02eee40
add clerk design struct
mikepitre Apr 10, 2025
f230278
clerk text field
mikepitre Apr 10, 2025
9fa5d7f
premade custom themes
mikepitre Apr 10, 2025
49ba2f3
primary button and text divider
mikepitre Apr 10, 2025
a4e7570
use color assets for clerk theme
mikepitre Apr 11, 2025
5f66f47
social buttons
mikepitre Apr 11, 2025
a40dc72
dynamic social button grid
mikepitre Apr 13, 2025
1425220
improve social button grid, add secured by clerk view
mikepitre Apr 15, 2025
ea61870
custom spinner
mikepitre Apr 15, 2025
f8a059d
passback isRunning from asyncbutton
mikepitre Apr 15, 2025
d765081
mock env and clerk, env values extension
mikepitre Apr 15, 2025
5f71dfc
custom textfield placeholder animation
mikepitre Apr 16, 2025
1ce02bd
scaling textfield animation
mikepitre Apr 16, 2025
975fd1a
adjust signinstart spacing, create applogoview
mikepitre Apr 16, 2025
599b90b
simplify text field animation
mikepitre Apr 16, 2025
52a056f
go back to scaling text field animation
mikepitre Apr 17, 2025
8ee2c2a
generate primary pressed color
mikepitre Apr 17, 2025
5c2451c
remove scale style button
mikepitre Apr 17, 2025
1ffa864
redo scaling text field animation for accessibility
mikepitre Apr 17, 2025
52f7a20
change sign in start text
mikepitre Apr 17, 2025
1355fa2
add option for secure text field and increase tappable area
mikepitre Apr 17, 2025
11cf09b
clerk button variations
mikepitre Apr 17, 2025
df6eeb7
addd reveal animation to textfield
mikepitre Apr 17, 2025
59bcd86
add identity preview view
mikepitre Apr 17, 2025
81778b9
use state for password
mikepitre Apr 17, 2025
6c18eb7
improve clerk text field focus transition
mikepitre Apr 17, 2025
afea7ba
rename sign in view state to auth state
mikepitre Apr 18, 2025
4ff6114
rename flowstep to step
mikepitre Apr 18, 2025
b9a50a8
flip reveal icon
mikepitre Apr 18, 2025
47d2e9f
buttons style disabled states
mikepitre Apr 18, 2025
89b65f2
autofocus password text field
mikepitre Apr 18, 2025
4e078d8
add arabic, chinese, greek and hindi translations
mikepitre Apr 18, 2025
f2b7d19
submit password
mikepitre Apr 18, 2025
9a78bb1
create header view
mikepitre Apr 18, 2025
e7bae37
create modifier to clerk focused border
mikepitre Apr 18, 2025
a72c116
otp field
mikepitre Apr 21, 2025
a9defb5
factor one code view
mikepitre Apr 21, 2025
bc0b50a
translations
mikepitre Apr 21, 2025
0d488df
add French and Italian localizations
mikepitre Apr 21, 2025
c1cc342
fix placeholder and animation on clerk text field
mikepitre Apr 21, 2025
e2fee49
get help view, factor sorting, starting sign in factor logic
mikepitre Apr 21, 2025
6fab4b6
passkey view, otp code prepare and attempt
mikepitre Apr 22, 2025
1eaa378
trigger passkey on appear
mikepitre Apr 22, 2025
0ab8baa
replace social button grid with custom layout
mikepitre Apr 23, 2025
e9917e5
factor one alternative methods view
mikepitre Apr 23, 2025
8f9071b
put AuthView in nav stack
mikepitre Apr 23, 2025
813cebf
remove auto auth with passkey
mikepitre Apr 23, 2025
580bb74
add can import statements to all clerkui swift files
mikepitre Apr 23, 2025
0e806f1
add or divider to alt methods view, add missing module param
mikepitre Apr 23, 2025
be25cb0
update symbols to icons
mikepitre Apr 24, 2025
9b729e5
otp resend timer
mikepitre Apr 24, 2025
7cc705d
otp improvements, resend functionality, localization
mikepitre Apr 28, 2025
9225f30
use existing sign in if available for authwithredirect static func
mikepitre Apr 28, 2025
3fc76a7
Revert "use existing sign in if available for authwithredirect static…
mikepitre Apr 28, 2025
2ec0da7
factor one code view verification states
mikepitre Apr 28, 2025
de6468c
rename hide keyboard to dismiss keyboard
mikepitre Apr 28, 2025
5d4e488
rebase fixes
mikepitre Apr 28, 2025
f532151
phone number field and handling
mikepitre Apr 29, 2025
c2fb974
auth with passkey on appear
mikepitre Apr 29, 2025
3d954be
fix identifier switcher text, add localization
mikepitre Apr 29, 2025
d39ac94
improve text field animation timing
mikepitre Apr 29, 2025
c1f0ffb
phone number formatting
mikepitre May 1, 2025
139b92d
speed up identifier field transition
mikepitre May 1, 2025
0206248
UserButton and UserButtonPopover
mikepitre May 1, 2025
60fe7ea
localizations
mikepitre May 1, 2025
a76b499
remember identifier and phone number
mikepitre May 1, 2025
67cafd8
mail to with support email
mikepitre May 1, 2025
3ddd415
replace can import SwiftUI with os(iOS)
mikepitre May 1, 2025
fcebb0f
add missing compiler flag to view
mikepitre May 1, 2025
9dfe158
warning fixes
mikepitre May 2, 2025
0404f90
fix clerk entry swift 6 warnings
mikepitre May 2, 2025
87a915b
change user default key names
mikepitre May 2, 2025
39dc8e0
add background color to use button popover
mikepitre May 2, 2025
fd377df
start on phone if filled out but identifier is not
mikepitre May 2, 2025
d3b8ade
disable passkey button on appear
mikepitre May 2, 2025
0a19015
only animate identifier field on toggle, not appear
mikepitre May 2, 2025
e22aa76
add forgot password button
mikepitre May 5, 2025
1e47774
add japanese and korean languages
mikepitre May 5, 2025
d4aa652
only use done button for phone number input
mikepitre May 5, 2025
a98adbb
multi consumer event emitter
mikepitre May 6, 2025
8755a41
account switching
mikepitre May 6, 2025
998ee37
add translations
mikepitre May 6, 2025
72aaa0b
sort active session to top of account switcher
mikepitre May 6, 2025
e9f857a
use list to workaround unwanted tap in ios 18 scroll bug
mikepitre May 7, 2025
f75ac94
Revert "use list to workaround unwanted tap in ios 18 scroll bug"
mikepitre May 7, 2025
18e4716
workaround for ios 18 bug button touches not cancelled in scroll
mikepitre May 7, 2025
e5fb1e8
use primary color for image placeholder
mikepitre May 7, 2025
1f42a68
forgot password, set new password UI
mikepitre May 7, 2025
e343e18
localization
mikepitre May 7, 2025
3f79989
fix sensory feedback and incorrect code retrying
mikepitre May 7, 2025
99c5dc5
fix double prepare for reset factors
mikepitre May 8, 2025
1b0fde0
create error view
mikepitre May 8, 2025
3eb3773
error presenting sheet and modifier
mikepitre May 8, 2025
d95dadd
rename setnewpasswordview, use error sheet for prepare errors
mikepitre May 8, 2025
de8d6c1
create user profile view
mikepitre May 9, 2025
4f42caa
add german localization
mikepitre May 9, 2025
ba47b36
remove app logo from auth views except start
mikepitre May 9, 2025
1fef706
wip user profile detail
mikepitre May 9, 2025
b4dd148
use system toolbar and scroll background color
mikepitre May 12, 2025
1ff9793
add action buttons to profile detail
mikepitre May 12, 2025
b61e685
user profile wip
mikepitre May 12, 2025
6aa4012
badge view
mikepitre May 13, 2025
77caf87
use new badges
mikepitre May 13, 2025
e81812b
add user check for back up codes
mikepitre May 13, 2025
b8cbc15
remove semi bold from some user profile rows
mikepitre May 13, 2025
a080556
change primary to default for mfa badge
mikepitre May 13, 2025
6f00c57
user profile security UI
mikepitre May 13, 2025
7a71459
adjust connected account and chevron color
mikepitre May 13, 2025
19f1f79
wip
mikepitre May 13, 2025
2e816ff
repurpose factor code and alt methods views for second factor
mikepitre May 13, 2025
beee887
sort alternative second factors
mikepitre May 13, 2025
539871b
use focus state on code view instead of environment dismiss keyboard
mikepitre May 14, 2025
932c229
second factor backup codes
mikepitre May 14, 2025
195356e
hide use another method on reset code factor
mikepitre May 14, 2025
22b45ce
use partial formatter for string extension
mikepitre May 14, 2025
78a8cb9
use any available reset factor when identifying isnt available
mikepitre May 14, 2025
8ee3774
add prefix to string phone formatting extension
mikepitre May 14, 2025
c1b2ba8
set new password
mikepitre May 14, 2025
a2f2f50
update profile wip
mikepitre May 14, 2025
f219a5a
user profile update functionality
mikepitre May 15, 2025
19899a3
move uiimage extension to own file
mikepitre May 15, 2025
535d8a1
add email to account
mikepitre May 16, 2025
9059f16
add localized strings
mikepitre May 27, 2025
84b326a
add phone number
mikepitre May 27, 2025
14da305
set as primary and remove email, phone and connected accounts
mikepitre May 27, 2025
3c63ef7
localizations
mikepitre May 27, 2025
fbc5526
connect and remove external accounts
mikepitre May 28, 2025
676a409
localize
mikepitre May 28, 2025
58dcb8b
dynamically sized sheets without keyboards
mikepitre May 28, 2025
3eec2ed
wip
mikepitre May 28, 2025
7ddf7c1
fix 2 factor after oauth
mikepitre May 28, 2025
1d031f9
localize
mikepitre May 28, 2025
1af098e
design tweaks
mikepitre May 29, 2025
24a8ad4
error view background color
mikepitre May 29, 2025
e5fe0ef
get client when error is resource not found
mikepitre May 29, 2025
cdc009c
user profile badges, verify existing
mikepitre May 29, 2025
bbd80e7
hide add account when all connected, animate account switcher
mikepitre May 29, 2025
85e5844
localize
mikepitre May 29, 2025
d2db9bb
add paskey
mikepitre May 29, 2025
0dac4f3
localize
mikepitre May 29, 2025
3950505
sign out of device, passkey row, animations, localize
mikepitre May 29, 2025
c522584
fix passkey sort order
mikepitre May 29, 2025
d112848
don't catch ASAuthErrors with messages
mikepitre May 30, 2025
903e899
adjust update user profile spacing
mikepitre May 30, 2025
1b39393
rename passkeys, fetch client on all user profile screens
mikepitre May 30, 2025
99eeb73
localize
mikepitre May 30, 2025
360016d
remove copy pasted textfield modifiers
mikepitre May 30, 2025
161d109
fetch device sessions whenever use changes
mikepitre May 30, 2025
0afc149
show external accounts with errors, remove verify action from externa…
mikepitre May 30, 2025
b54109e
delete account
mikepitre Jun 2, 2025
ec831bb
choose mfa sheet
mikepitre Jun 3, 2025
5de272e
add sms mfa, remove 2fa methods
mikepitre Jun 6, 2025
c0ef480
backup codes after adding phone code mfa
mikepitre Jun 9, 2025
aad5c1f
restructure user profile detail rows
mikepitre Jun 10, 2025
6d5a2ee
remove user button fixed size, backup codes toolbar title
mikepitre Jun 11, 2025
6b083c1
Mike/liquid glass (#229)
mikepitre Jun 11, 2025
9e27fb9
localization
mikepitre Jun 11, 2025
7ce1a78
add auth app mfa
mikepitre Jun 12, 2025
fb08208
localization
mikepitre Jun 12, 2025
18b3b43
regen backup codes, create totp before showing totp view
mikepitre Jun 12, 2025
facbd03
secured by clerk footer reusable view
mikepitre Jun 13, 2025
2e4efef
reset password wip
mikepitre Jun 16, 2025
851cc00
fix typo
mikepitre Jun 17, 2025
e442b21
change password wip
mikepitre Jun 18, 2025
a68bf98
update textfield animation
mikepitre Jun 18, 2025
9169ab1
2 step change password flow
mikepitre Jun 18, 2025
14f66fc
help ios heuristics on set new password view
mikepitre Jun 18, 2025
623397e
dynamically add action button to error sheet based on error
mikepitre Jun 18, 2025
6c70a7c
validate new and confirm match
mikepitre Jun 18, 2025
fc961de
add vs reset password
mikepitre Jun 18, 2025
0e381ff
go to alternative methods if reset not available
mikepitre Jun 20, 2025
451bb25
add isEmptyTrimmed helper
mikepitre Jun 20, 2025
3db7e5b
string helpers for identifier types
mikepitre Jun 20, 2025
460f80e
Mike/sign in or up (#232)
mikepitre Jun 26, 2025
db12b4f
move field vars to auth state
mikepitre Jun 26, 2025
40e8523
show get help view when no factors available
mikepitre Jun 26, 2025
39b3649
use scrollDismissesKeyboard instead of keyboard toolbar item
mikepitre Jun 26, 2025
ac8e4b3
auto dismiss auth view when sign in or up completed
mikepitre Jun 27, 2025
7ef0231
signInOrUp, sign in, sign up functionality
mikepitre Jun 27, 2025
47c247b
change auth view dismiss parameter name
mikepitre Jun 27, 2025
eac591a
set shared environment when env fetched
mikepitre Jun 27, 2025
bf9aeb1
hide and show clerk branding
mikepitre Jun 27, 2025
5899c1c
enterprise sso, conditionally show user profile detail sections
mikepitre Jun 27, 2025
226e59c
rename user profile param
mikepitre Jun 27, 2025
a66d740
remove account delete before reconnect
mikepitre Jun 30, 2025
79dbf22
create Settings struct for clerk config
mikepitre Jun 30, 2025
772f08b
persist client in keychain
mikepitre Jun 30, 2025
54c03f4
add environment caching
mikepitre Jun 30, 2025
1125ca4
add client assignment for async let in clerk load
mikepitre Jun 30, 2025
85811c2
remove spinner view when user nil for user profile view
mikepitre Jun 30, 2025
58123f7
remove old debugMode var from Clerk
mikepitre Jun 30, 2025
010c06d
ClerkLogger
mikepitre Jun 30, 2025
879c19a
dont show cancellation error for fetching sessions
mikepitre Jun 30, 2025
bab800c
update user profile placeholder
mikepitre Jun 30, 2025
85c01f2
improve error context message
mikepitre Jul 1, 2025
9a5d47f
add error logging to ErrorThrowingMiddleware
mikepitre Jul 1, 2025
57d1761
make ClerkLogger internal
mikepitre Jul 1, 2025
000da55
remove presentationBackground modifiers
mikepitre Jul 1, 2025
2550f03
add missing color modifier
mikepitre Jul 1, 2025
1d23ea2
set backgrounds and presentation backgrounds
mikepitre Jul 1, 2025
5b5a22c
cancellation error helper
mikepitre Jul 1, 2025
1d32351
use lazy vstacks
mikepitre Jul 1, 2025
2e2fe48
totp verify back button
mikepitre Jul 1, 2025
68eeb6f
dont show placeholder in debug run
mikepitre Jul 1, 2025
d7f3f84
if session is last session, dismiss early
mikepitre Jul 1, 2025
b8e2e5f
only present verified numbers for mfa
mikepitre Jul 1, 2025
b39879f
Update localization strings for various authentication and profile sc…
mikepitre Jul 1, 2025
2f5f2bb
component docs
mikepitre Jul 1, 2025
e722103
readme updates
mikepitre Jul 1, 2025
d55c8f2
Add secure nonce generation for Sign in with Apple authentication (#235)
mikepitre Jul 2, 2025
3a472b0
add config steps to readme
mikepitre Jul 3, 2025
66f241f
flip user profile isDismissable default
mikepitre Jul 3, 2025
b6cb058
fix readme typo
mikepitre Jul 3, 2025
d42f44c
custom modifier for pre ios 26 short sheets
mikepitre Jul 23, 2025
719cb67
update factory kit to 2.5.3 (#237)
mikepitre Jul 24, 2025
342cf04
make security view non lazy
mikepitre Jul 27, 2025
dc97f6a
only show active device when activity present
mikepitre Jul 28, 2025
d300957
set auth step to sign up status
mikepitre Jul 28, 2025
689487e
Mike/clerk code improvements (#239)
mikepitre Jul 29, 2025
bfc36fa
trim readme
mikepitre Jul 29, 2025
1889cfb
update swift format config
mikepitre Jul 29, 2025
51e6105
remove trailing commas from multiline collections
mikepitre Jul 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 6 additions & 3 deletions .swift-format
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
{
"version": 1,
"lineLength": 200,
"indentConditionalCompilationBlocks" : false,
"multiElementCollectionTrailingCommas" : false,
"lineLength": 1000,
"indentation": {
"spaces": 2
"spaces": 4
},
"rules": {
"OrderedImports": true,
"AllPublicDeclarationsHaveDocumentation" : true,
"OrderedImports": true
}
}
23 changes: 15 additions & 8 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,38 @@ import PackageDescription

let package = Package(
name: "Clerk",
defaultLocalization: "en",
platforms: [
.iOS(.v17),
.macCatalyst(.v17),
.macOS(.v14),
.watchOS(.v10),
.tvOS(.v17),
.visionOS(.v1),
.visionOS(.v1)
],
products: [
.library(name: "Clerk", targets: ["Clerk"])
],
dependencies: [
.package(url: "https://github.com/hmlongco/Factory", from: "2.0.0"),
.package(url: "https://github.com/kean/Get", .upToNextMajor(from: "2.2.1")),
.package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0"),
.package(url: "https://github.com/hmlongco/Factory", from: "2.5.3"),
.package(url: "https://github.com/onevcat/Kingfisher.git", .upToNextMajor(from: "8.0.0")),
.package(url: "https://github.com/WeTransfer/Mocker.git", .upToNextMajor(from: "3.0.0")),
.package(url: "https://github.com/marmelroy/PhoneNumberKit", .upToNextMajor(from: "4.0.0")),
.package(url: "https://github.com/hmlongco/RequestBuilder", branch: "main"),
.package(url: "https://github.com/auth0/SimpleKeychain", .upToNextMajor(from: "1.0.0")),
.package(url: "https://github.com/pointfreeco/swift-concurrency-extras", .upToNextMajor(from: "1.3.1")),
.package(url: "https://github.com/pointfreeco/swift-concurrency-extras", .upToNextMajor(from: "1.3.1"))
],
targets: [
.target(
name: "Clerk",
dependencies: [
.product(name: "Factory", package: "Factory"),
.product(name: "Get", package: "Get"),
.product(name: "SimpleKeychain", package: "SimpleKeychain"),
.product(name: "Algorithms", package: "swift-algorithms"),
.product(name: "FactoryKit", package: "Factory"),
.product(name: "Kingfisher", package: "Kingfisher"),
.product(name: "PhoneNumberKit", package: "PhoneNumberKit"),
.product(name: "RequestBuilder", package: "RequestBuilder"),
.product(name: "SimpleKeychain", package: "SimpleKeychain")
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
Expand All @@ -40,7 +47,7 @@ let package = Package(
dependencies: [
"Clerk",
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "Mocker", package: "Mocker"),
.product(name: "Mocker", package: "Mocker")
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
Expand Down
188 changes: 3 additions & 185 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,15 @@
<h1 align="center">
Official Clerk iOS SDK
</h1>
<p align="center">
<strong>
Clerk helps developers build user management. We provide streamlined user experiences for your users to sign up, sign in, and manage their profile.
</strong>
</p>


[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fclerk%2Fclerk-ios%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/clerk/clerk-ios)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fclerk%2Fclerk-ios%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/clerk/clerk-ios)
[![chat on Discord](https://img.shields.io/discord/856971667393609759.svg?logo=discord)](https://clerk.com/discord)
[![documentation](https://img.shields.io/badge/documentation-clerk-green.svg)](https://clerk.com/docs)
[![twitter](https://img.shields.io/twitter/follow/ClerkDev?style=social)](https://twitter.com/intent/follow?screen_name=ClerkDev)

---

**Clerk is Hiring!**

Would you like to work on Open Source software and help maintain this repository? [Apply today!](https://jobs.ashbyhq.com/clerk)

---
The Clerk iOS SDK gives you access to prebuilt SwiftUI components, observable state management, and helpers to make user management easier.

## 🚀 Get Started with Clerk

Expand All @@ -55,184 +45,12 @@ dependencies: [
]
```

## 🛠️ Usage

First, configure Clerk in your app's entry point:

```swift
import SwiftUI
import Clerk

@main
struct ClerkQuickstartApp: App {
@State private var clerk = Clerk.shared

var body: some Scene {
WindowGroup {
ContentView()
.environment(clerk)
.task {
clerk.configure(publishableKey: "your_publishable_key")
try? await clerk.load()
}
}
}
}
```

Now in your views, you can conditionally render content based on the user's session:

```swift
import SwiftUI
import Clerk

struct ContentView: View {
@Environment(Clerk.self) private var clerk

var body: some View {
VStack {
if let user = clerk.user {
Text("Hello, \(user.id)")
} else {
Text("You are signed out")
}
}
}
}
```

### Authentication

#### Sign Up with Email and Perform Verification
```swift
// Create a sign up
var signUp = try await SignUp.create(
strategy: .standard(emailAddress: "user@example.com", password: "••••••••••••")
)

// Check if the SignUp needs the email address verified and send an OTP code via email.
if signUp.unverifiedFields.contains("email_address") {
signUp = try await signUp.prepareVerification(strategy: .emailCode)
}

// After collecting the OTP code from the user, attempt verification
signUp = try await signUp.attemptVerification(strategy: .emailCode(code: "12345"))
```

#### Passwordless Sign In
```swift
// Create the sign in
var signIn = try await SignIn.create(
strategy: .identifier("user@example.com", strategy: .emailCode())
)

// After collecting the OTP code from the user, attempt verification
signIn = try await signIn.attemptFirstFactor(strategy: .emailCode(code: "12345"))
```

#### Sign In with OAuth (e.g. Google, Github, etc.)
```swift
try await SignIn.authenticateWithRedirect(strategy: .oauth(provider: .google))
```

#### Native Sign in with Apple
```swift
// Use the Clerk SignInWithAppleHelper class to get your Apple credential
let credential = try await SignInWithAppleHelper.getAppleIdCredential()

// Convert the identityToken data to String format
guard let idToken = credential.identityToken.flatMap({ String(data: $0, encoding: .utf8) }) else { return }

// Authenticate with Clerk
try await SignIn.authenticateWithIdToken(provider: .apple, idToken: idToken)
```

#### Forgot Password
```swift
// Create a sign in and send an OTP code to verify the user owns the email.
var signIn = try await SignIn.create(
strategy: .identifier("user@example.com", strategy: .resetPasswordEmailCode())
)

// After collecting the OTP code from the user, attempt verification.
signIn = try await signIn.attemptFirstFactor(strategy: .resetPasswordEmailCode(code: "12345"))

// Set a new password to complete the process.
signIn = try await signIn.resetPassword(.init(password: "••••••••••••", signOutOfOtherSessions: true))
```

#### Sign Out
```swift
try await clerk.signOut()
```

### User Management

#### Update User Profile
```swift
try await user.update(.init(firstName: "John", lastName: "Appleseed"))
```

#### Update User Profile Image
```swift
let imageData = try await photosPickerItem.loadTransferable(type: Data.self)
try await user.setProfileImage(imageData: imageData)
```

#### Add Phone Number
```swift
// Create a new phone number on the user's account
var newPhoneNumber = try await user.createPhoneNumber("5555550100")

// Send an OTP verification code via SMS to the phone number
newPhoneNumber = try await newPhoneNumber.prepareVerification()

// After collecting the OTP code from the user, attempt verification.
newPhoneNumber = try await newPhoneNumber.attemptVerification(code: "12345")
```

#### Link an External Account
```swift
let externalAccount = try await user.createExternalAccount(provider: .github)
try await externalAccount.reauthorize()
```

### Session Tokens
```swift
if let token = try await Clerk.shared.session?.getToken()?.jwt {
headers["Authorization"] = "Bearer \(token)"
}
```

For a full set of features and functionality, please see our docs!
## 🎓 Docs

- [iOS SDK Reference](https://swiftpackageindex.com/clerk/clerk-ios/main/documentation/clerk)
- [Clerk iOS](https://clerk.com/docs/references/ios/overview)
- [Quickstart](https://clerk.com/docs/quickstarts/ios)
- [Custom Flows](https://clerk.com/docs/custom-flows/overview)

## ✅ Supported Features

| Feature | iOS Support
--- | :---:
Email/Phone/Username Authentication | ✅
Email Code Verification | ✅
SMS Code Verification | ✅
Multi-Factor Authentication (TOTP / SMS) | ✅
Sign in / Sign up with OAuth | ✅
Native Sign in with Apple | ✅
Session Management | ✅
Multi-Session Applications | ✅
Forgot Password | ✅
User Management | ✅
Passkeys | ✅
Enterprise SSO (SAML) | ✅
Device Attestation | ✅
Organizations | ✅
Prebuilt UI Components | 🚧
Magic Links | ❌
Web3 Wallet | ❌

## 🚢 Release Notes

Curious what we shipped recently? Check out our [changelog](https://clerk.com/changelog)!
Expand Down
45 changes: 6 additions & 39 deletions Sources/Clerk/APIClient/ClerkAPIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,15 @@
// Created by Mike Pitre on 10/2/23.
//

import Factory
import FactoryKit
import Foundation
import Get

final class ClerkAPIClientDelegate: APIClientDelegate, Sendable {

func client(_ client: APIClient, willSendRequest request: inout URLRequest) async throws {
await HeaderMiddleware.process(&request)
QueryItemMiddleware.process(&request)
try URLEncodedFormMiddleware.process(&request)
}

func client(_ client: APIClient, validateResponse response: HTTPURLResponse, data: Data, task: URLSessionTask) throws {
DeviceTokenSavingMiddleware.process(response)
ClientSyncingMiddleware.process(data)
EventEmitterMiddleware.process(data)
try ErrorThrowingMiddleware.process(response, data: data)
}

func client(_ client: APIClient, shouldRetry task: URLSessionTask, error: any Error, attempts: Int) async throws -> Bool {
guard attempts == 1 else {
return false
}

if try await DeviceAssertionMiddleware.process(task: task, error: error) {
return true
}

if try await InvalidAuthMiddleware.process(task: task, error: error) {
return true
}

return false
}

}
import RequestBuilder

extension Container {

var apiClient: Factory<APIClient> {
self { APIClient(baseURL: URL(string: "")) }
.cached
}
var apiClient: Factory<URLSessionManager> {
self { BaseSessionManager(base: URL(string: ""), session: .shared) }
.cached
}

}
36 changes: 36 additions & 0 deletions Sources/Clerk/APIClient/Extensions/URLRequestBuilder+Ext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// URLRequestBuilder+Ext.swift
// Clerk
//
// Created by Mike Pitre on 1/8/25.
//

import FactoryKit
import Foundation
import RequestBuilder

extension URLRequestBuilder {

/// Adds the current Clerk session id to request URL.
@discardableResult @MainActor
func addClerkSessionId() -> Self {
map {
if let url = request.url, var components = URLComponents(url: url, resolvingAgainstBaseURL: false) {
components.queryItems = (components.queryItems ?? []) + [.init(name: "_clerk_session_id", value: Clerk.shared.session?.id)]
$0.request.url = components.url
}
}
}

/// Given an encodable data type, sets the request body to x-www-form-urlencoded data .
@discardableResult
public func body<DataType: Encodable>(formEncode data: DataType) -> Self {
return map {
if let data: Data = try? URLEncodedFormEncoder(keyEncoding: .convertToSnakeCase).encode(data) {
$0.add(value: "application/x-www-form-urlencoded", forHeader: "Content-Type")
$0.request.httpBody = data
}
}
}

}
Loading
Loading