Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
c8b4e8c
feat: add native UserButton and UserProfile components for iOS
chriscanin Dec 3, 2025
39fb327
feat(clerk): add getSession and signOut methods to ClerkExpoModule an…
chriscanin Dec 3, 2025
6d393b8
feat(user-button): fetch and display user details in UserButton compo…
chriscanin Dec 3, 2025
96dcbbc
Refactor code structure for improved readability and maintainability
chriscanin Dec 4, 2025
9962fdc
Merge remote-tracking branch 'origin/main' into chris/mobile-342-brid…
chriscanin Jan 7, 2026
82edb61
feat(clerk): integrate Clerk SDK for Android with authentication and …
chriscanin Jan 8, 2026
13f7a46
Merge remote-tracking branch 'origin/main' into chris/mobile-343-brid…
chriscanin Jan 16, 2026
b2b12c2
feat(clerk): enhance error handling and user session management in Cl…
chriscanin Jan 22, 2026
638887d
feat(clerk): iOS bridging is working. Only minor debugging left to do.
chriscanin Jan 23, 2026
aba2c72
refactor: Revamp Clerk bridging integration for improved session hand…
chriscanin Jan 23, 2026
36780e7
feat(clerk): update Android integration with new dependency versions …
chriscanin Jan 23, 2026
1a0b4ee
feat: Update Clerk SDK versions and enhance Android packaging
chriscanin Jan 24, 2026
04ba08f
feat: add AuthView component for native authentication flows
chriscanin Jan 27, 2026
d7d2300
feat(clerk): enable native module support and fix module config
chriscanin Feb 3, 2026
7a295ab
feat(expo): add .md suggestion
chriscanin Feb 3, 2026
d5408eb
fix(react): conditionally load UI scripts to prevent document.createE…
chriscanin Feb 4, 2026
184feae
feat: enhance native module support for core-3 and add hooks for auth…
chriscanin Feb 10, 2026
21945eb
clean up images from maestro testing, should not have been commited.
chriscanin Feb 11, 2026
cfc635d
Fix android build for core-3 components release.
chriscanin Feb 12, 2026
73a0f6d
Continued fixes for android build for core-3 components release.
chriscanin Feb 12, 2026
956cdc9
fix: improve native bridge quality and prevent coroutine leaks in And…
chriscanin Feb 13, 2026
b8127fd
Merge origin/main and resolve conflicts
chriscanin Feb 13, 2026
519479b
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Feb 13, 2026
2283b41
Delete .changeset/modern-hornets-fold.md
chriscanin Feb 13, 2026
4559673
fix(expo): address CodeRabbit review feedback
chriscanin Feb 13, 2026
52aa40b
fix(expo): remove unused isSignedIn destructure in UserButton
chriscanin Feb 13, 2026
c36a4a6
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Feb 13, 2026
95c714d
fix(expo): address remaining CodeRabbit review issues (round 2)
chriscanin Feb 13, 2026
2a5d8f1
chore: update changeset to reflect feature scope
chriscanin Feb 13, 2026
e1ad295
fix(expo): address final CodeRabbit review issues (round 3)
chriscanin Feb 13, 2026
4995b61
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Feb 13, 2026
31eccd6
fix(react): remove non-null assertion to satisfy ESLint rule
chriscanin Feb 13, 2026
5aebb5e
fix(expo): resolve all ESLint errors in @clerk/expo
chriscanin Feb 13, 2026
6aa39b3
- Improved session synchronization by writing the JS SDK's client JWT…
chriscanin Feb 24, 2026
d0e7866
App should now have 0 native internals exposed to the user. This is t…
chriscanin Feb 24, 2026
ece2b92
feat(android): enable new architecture support in build.gradle and up…
chriscanin Feb 24, 2026
f66b79c
feat(android): implement new architecture support and refactor Clerk …
chriscanin Feb 24, 2026
d03b662
Update lockfile after expo-modules-core removal
chriscanin Feb 24, 2026
ddc58d3
Merge remote-tracking branch 'origin/main' into chris/mobile-405-reac…
chriscanin Feb 24, 2026
eb3e46b
Fix lint errors in @clerk/expo spec files and imports
chriscanin Feb 24, 2026
6450ede
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Feb 25, 2026
02771e0
Codderrabit comment resolutions
chriscanin Feb 26, 2026
6123d1a
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Feb 26, 2026
5b09fbf
fix(expo): drop support for Expo 50-52 and update peer dependency to …
chriscanin Feb 26, 2026
886615e
fix(expo): make expo-auth-session and expo-web-browser optional depen…
chriscanin Feb 26, 2026
608112e
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Feb 26, 2026
8fa8943
fix(expo): use TurboModuleRegistry.get instead of getEnforcing for Cl…
chriscanin Feb 26, 2026
5d321c9
fix(clerk-js): skip DOM-based captcha in React Native environments
chriscanin Feb 27, 2026
44bee1d
fix(expo): use UnsafeObject instead of object in TurboModule specs
chriscanin Feb 27, 2026
e238e49
feat(expo): add useUserProfileModal hook, remove callback props, pin …
chriscanin Mar 2, 2026
c6c86da
feat(expo): remove callback props from AuthView, add keychain customi…
chriscanin Mar 2, 2026
11c55c0
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Mar 2, 2026
d1c968e
fix(expo): resolve lint errors in native module specs and providers
chriscanin Mar 2, 2026
9aa45b5
fix(expo): suppress consistent-type-imports for dynamic optional imports
chriscanin Mar 2, 2026
8b4dc22
chore: simplify native components changeset to 3 bullet points
chriscanin Mar 2, 2026
5f3be94
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
jacekradko Mar 3, 2026
0d6afa8
fix(expo): captcha guard, keychain customization, non-enforcing nativ…
chriscanin Mar 4, 2026
be91033
Merge remote-tracking branch 'origin/main' into chris/mobile-405-reac…
chriscanin Mar 4, 2026
5485e1d
refactor(expo): consolidate CLERK_CLIENT_JWT_KEY into shared constant
chriscanin Mar 4, 2026
57db664
refactor(expo): use tokenCache abstraction instead of direct SecureSt…
chriscanin Mar 4, 2026
b12c46f
fix(expo): use ClerkRuntimeError with error codes in native views
chriscanin Mar 4, 2026
37d0dbc
fix(expo): add max poll limit to native session fallback polling
chriscanin Mar 4, 2026
4f48db6
fix(expo): distinguish modal dismissal from unexpected errors
chriscanin Mar 4, 2026
27c4ca3
fix(expo): correct error handling for presentUserProfile
chriscanin Mar 4, 2026
2d87892
fix(expo): guard presentUserProfile error logging with __DEV__
chriscanin Mar 4, 2026
21933a6
refactor(expo): hoist isClerkNetworkError helper, remove unnecessary …
chriscanin Mar 4, 2026
b5d4d5e
refactor(expo): move pk change reset to useEffect
chriscanin Mar 4, 2026
14ae51a
refactor(expo): clean up eslint disables in codegen spec files
chriscanin Mar 4, 2026
ff5fe97
chore(expo): remove generated app.plugin.d.ts build artifacts
chriscanin Mar 4, 2026
16b94ca
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Mar 4, 2026
b58159e
fix(expo): fix import sort order after merge from main
chriscanin Mar 4, 2026
5d9bc78
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Mar 5, 2026
aa76e5a
fix(expo): fix iOS auth event handling for password reset and email c…
chriscanin Mar 5, 2026
4c158c5
fix(expo): bump clerk-android to 1.0.5 to fix reset password flow
chriscanin Mar 5, 2026
78fb57c
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Mar 5, 2026
0be41ac
Merge branch 'main' into chris/mobile-405-react-native-components-rel…
chriscanin Mar 5, 2026
ca6c5b6
chore(upgrade): remove expo-native-components upgrade guide
chriscanin Mar 5, 2026
42728b9
fix(expo): bump clerk-android to 1.0.6
chriscanin Mar 5, 2026
d7819f8
temporary comment out org checker step
wobsoriano Mar 5, 2026
98dbc88
temporary comment out org checker step
wobsoriano Mar 5, 2026
83f0903
revert previous commit
wobsoriano Mar 5, 2026
cec4ab5
retry
wobsoriano Mar 5, 2026
0962a90
revert ci
wobsoriano Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/fix-native-bridge-quality.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@clerk/expo': minor
---

- Add native React Native components (AuthView, UserButton, UserProfileView) with `useUserProfileModal()` hook
- Add native Google Sign-In via Credential Manager (Android) and ASAuthorization (iOS)
- Update to Core-3 Signal APIs
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ sessions.pem
# pkglab / Verdaccio local registry
.verdaccio

# yalc
.yalc/
yalc.lock

# Release preflight
.release-artifacts/

Expand Down
279 changes: 279 additions & 0 deletions packages/expo/NATIVE_IOS_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
# Native iOS Setup for @clerk/clerk-expo

This guide explains how to use Clerk's native iOS components in your Expo or React Native application.

## Overview

`@clerk/clerk-expo` supports two implementations:

1. **Native-First (Recommended)**: Uses Clerk's native iOS Swift UI components for the best user experience
2. **React Native**: Cross-platform React Native components that work everywhere

## Feature Comparison

| Feature | Native iOS (Swift UI) | React Native |
| -------------------- | ------------------------------------ | ------------------------------- |
| **UI/UX** | Native iOS design, follows Apple HIG | Cross-platform design |
| **Performance** | Native Swift performance | JavaScript bridge overhead |
| **Bundle Size** | Smaller JS bundle | Larger JS bundle |
| **Customization** | Limited to Clerk iOS theming | Full React Native customization |
| **Platform Support** | iOS only | iOS, Android, Web |
| **Build Method** | Requires native build (EAS/Xcode) | Works with Expo Go |
| **Face ID/Touch ID** | Native biometric integration | Via expo-local-authentication |
| **Passkeys** | Native passkey support | Limited support |
| **OAuth** | Native SFAuthenticationSession | WebBrowser-based |

---

## Setup Instructions

### For Expo Users (Recommended)

#### Prerequisites

- Expo SDK 50 or later
- EAS Build account (native builds required)
- iOS deployment target 15.1+

#### 1. Install the Package

```bash
npx expo install @clerk/clerk-expo
```

#### 2. Add the Expo Config Plugin

In your `app.json` or `app.config.js`:

```json
{
"expo": {
"plugins": [["@clerk/clerk-expo/app.plugin"]]
}
}
```

#### 3. Configure Your App

```tsx
// app/_layout.tsx
import { ClerkProvider } from '@clerk/clerk-expo';

export default function RootLayout() {
return (
<ClerkProvider publishableKey={process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY}>
{/* Your app content */}
</ClerkProvider>
);
}
```

#### 4. Use Native Components

```tsx
// app/(auth)/sign-in.tsx
import { SignIn } from '@clerk/clerk-expo/native';
import { useRouter } from 'expo-router';

export default function SignInScreen() {
const router = useRouter();

return (
<SignIn
mode='signIn'
onSuccess={() => router.replace('/(home)')}
onError={error => console.error('Sign in error:', error)}
/>
);
}
```

#### 5. Build with EAS

The native iOS components require a native build:

```bash
# Development build
eas build --profile development --platform ios

# Install on simulator
eas build:run --profile development --platform ios

# Production build
eas build --profile production --platform ios
```

**Important**: Native iOS components **will not work** with Expo Go. You must create a development build.

---

### For React Native CLI Users

If you're using React Native without Expo, you'll need to manually add the clerk-ios Swift package.

#### Prerequisites

- React Native 0.70 or later
- CocoaPods
- Xcode 14+
- iOS deployment target 15.1+

#### 1. Install the Package

```bash
npm install @clerk/clerk-expo
# or
yarn add @clerk/clerk-expo
```

#### 2. Install iOS Dependencies

```bash
cd ios && pod install && cd ..
```

#### 3. Add clerk-ios Swift Package in Xcode

1. Open your `.xcworkspace` file in Xcode
2. Select your project in the Project Navigator
3. Select your app target
4. Go to the "Package Dependencies" tab
5. Click the "+" button
6. Enter the repository URL: `https://github.com/clerk/clerk-ios.git`
7. Select "Up to Next Major Version" with minimum version `0.68.1`
8. Ensure the "Clerk" product is selected for your target
9. Click "Add Package"

#### 4. Verify Installation

Build your project to ensure the Swift package is properly linked:

```bash
npx react-native run-ios
```

---

## Using React Native Components Instead

If you want to use the cross-platform React Native components (works with Expo Go), import from the main package:

```tsx
import { SignIn } from '@clerk/clerk-expo';
// NOT from '@clerk/clerk-expo/native'
```

### When to Use React Native Components

- Testing in Expo Go
- Need Android support
- Want full UI customization
- Don't need native iOS features (Face ID, Passkeys)

### When to Use Native iOS Components

- Building a production iOS app
- Want the best iOS user experience
- Need native biometric authentication
- Want smaller JavaScript bundle size
- Need passkey support

---

## API Reference

### Native SignIn Component

```tsx
import { SignIn } from '@clerk/clerk-expo/native';

<SignIn
mode="signIn" | "signUp" | "signInOrUp"
isDismissable={boolean}
onSuccess={(data) => void}
onError={(error) => void}
/>
```

**Props:**

- `mode`: Authentication mode (default: `"signInOrUp"`)
- `isDismissable`: Whether the view can be dismissed (default: `true`)
- `onSuccess`: Callback when authentication succeeds
- `onError`: Callback when authentication fails

---

## Troubleshooting

### "Module 'Clerk' not found"

The clerk-ios Swift package isn't installed. Follow the manual setup steps above.

### "Expo Go doesn't show native components"

Native components require a development build. Run `eas build --profile development --platform ios`.

### Plugin doesn't add Swift package

The config plugin only runs during `expo prebuild` or `eas build`. If you're using a bare workflow, you'll need to add the package manually in Xcode.

### Build fails with Swift errors

Ensure your iOS deployment target is at least 15.1 in your `Podfile`:

```ruby
platform :ios, '15.1'
```

---

## Migration Guide

### From React Native Components to Native

1. Change your imports:

```tsx
// Before
import { SignIn } from '@clerk/clerk-expo';

// After
import { SignIn } from '@clerk/clerk-expo/native';
```

2. Create a development build (can't use Expo Go)
3. Test on a physical device or simulator

### From Native to React Native

1. Change your imports back:

```tsx
// Before
import { SignIn } from '@clerk/clerk-expo/native';

// After
import { SignIn } from '@clerk/clerk-expo';
```

2. Can now use Expo Go for testing

---

## Additional Resources

- [Clerk iOS SDK Documentation](https://github.com/clerk/clerk-ios)
- [Expo Config Plugins](https://docs.expo.dev/config-plugins/introduction/)
- [EAS Build Documentation](https://docs.expo.dev/build/introduction/)
- [Clerk Dashboard](https://dashboard.clerk.com/)

---

## Support

For issues related to:

- Native iOS components: [clerk-ios repository](https://github.com/clerk/clerk-ios/issues)
- Expo integration: [clerk-javascript repository](https://github.com/clerk/javascript/issues)
- General Clerk questions: [Clerk Discord](https://clerk.com/discord)
58 changes: 52 additions & 6 deletions packages/expo/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.compose' version '2.1.20'
}

// Required for React Native codegen to generate Fabric component descriptors
if (project.hasProperty("newArchEnabled") && project.newArchEnabled == "true") {
apply plugin: "com.facebook.react"
}

group = 'com.clerk.expo'
version = '1.0.0'
Expand All @@ -10,14 +18,19 @@ ext {
credentialsVersion = "1.3.0"
googleIdVersion = "1.1.1"
kotlinxCoroutinesVersion = "1.7.3"
clerkAndroidApiVersion = "1.0.6"
clerkAndroidUiVersion = "1.0.6"
composeVersion = "1.7.0"
activityComposeVersion = "1.9.0"
lifecycleVersion = "2.8.0"
}

def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

android {
namespace "expo.modules.clerk.googlesignin"
namespace "expo.modules.clerk"

compileSdk safeExtGet("compileSdkVersion", 36)

Expand All @@ -41,18 +54,33 @@ android {

kotlinOptions {
jvmTarget = "17"
// clerk-android is compiled with Kotlin 2.3.x, but Expo uses Kotlin 2.1.20.
// This flag allows the compiler to read metadata from a newer Kotlin version.
freeCompilerArgs += ['-Xskip-metadata-version-check']
}

buildFeatures {
compose = true
}

packaging {
resources {
excludes += ['META-INF/versions/9/OSGI-INF/MANIFEST.MF']
}
}

sourceSets {
main {
java.srcDirs = ['src/main/java']
java.srcDirs = ['src/main/java', "${project.buildDir}/generated/source/codegen/java"]
}
}
}

// Note: kotlin-stdlib exclusions are handled in the clerk-android-ui dependency declaration

dependencies {
// Expo modules core
implementation project(':expo-modules-core')
// React Native
implementation 'com.facebook.react:react-native:+'

// Credential Manager for Google Sign-In with nonce support
implementation "androidx.credentials:credentials:$credentialsVersion"
Expand All @@ -61,4 +89,22 @@ dependencies {

// Coroutines for async operations
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinxCoroutinesVersion"

// Clerk Android SDK with prebuilt UI
// Exclude kotlin-stdlib to prevent 2.3.0 from polluting the project
// Exclude okhttp to prevent version conflict with React Native's okhttp
implementation("com.clerk:clerk-android-ui:$clerkAndroidUiVersion") {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
exclude group: 'com.squareup.okhttp3', module: 'okhttp-urlconnection'
}

// Jetpack Compose for wrapping Clerk views
implementation "androidx.compose.ui:ui:$composeVersion"
implementation "androidx.compose.material3:material3:1.3.0"
implementation "androidx.activity:activity-compose:$activityComposeVersion"
implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleVersion"
}
Loading
Loading