Thank you for your interest in contributing to the Clerk iOS SDK! This guide will help you get started with development.
Run the setup command to install all required tools and configure git hooks:
make setupThis command will:
- Install the repo-pinned SwiftFormat version
- Install the repo-pinned SwiftLint version
- Set up the pre-commit hook to automatically format staged Swift files
- Configure Xcode file header templates for both
Clerk.xcworkspaceand Swift package workspace views - Create a
.keys.jsonfile for integration test configuration (if it doesn't exist) - Create
LocalSecrets.plistfiles for example apps fromLocalSecrets.template.plistfiles (if missing)
After running make setup, you're ready to start developing!
For Clerk employees only: After running make setup, you can optionally run make fetch-test-keys to automatically populate integration test keys from 1Password. This will automatically install 1Password CLI if needed. This requires:
- Access to Clerk's Shared vault in 1Password
- 1Password desktop app integration enabled (see 1Password CLI setup guide)
- macOS with Xcode 26+ installed
- Swift 6.2+
- Git
-
Make your code changes as usual
-
When committing, the pre-commit hook will automatically:
- Format all staged Swift files using SwiftFormat
- Re-stage the formatted files
- If formatting changes files, you'll need to commit again
-
Manual formatting (if needed):
make format # Format all Swift files make format-check # Check formatting without modifying files make update-swiftformat # Update the pinned SwiftFormat release
-
Linting (if needed):
make lint # Check for lint issues make lint-fix # Auto-fix lint issues where possible make update-swiftlint # Update the pinned SwiftLint release
-
Run all checks before pushing:
make check # Runs both format-check and lint
make setup- Install tools/hooks, configure Xcode file headers, and create example LocalSecrets plistsmake install-tools- Install pinned SwiftFormat and SwiftLintmake update-swiftformat- Update pinned SwiftFormat to the latest releasemake update-swiftlint- Update pinned SwiftLint to the latest releasemake install-hooks- Install the pre-commit hookmake install-xcode-template-macros- Sync Xcode file header templates for both workspace and package viewsmake create-example-local-secrets-plists- CreateLocalSecrets.plistfiles for examples if missingmake create-env- Create the.keys.jsonfile if missingmake format- Format all Swift files using SwiftFormatmake format-check- Check formatting without modifying files (for CI)make lint- Run SwiftLint to check code qualitymake lint-fix- Run SwiftLint with auto-fix where possiblemake check- Run both format-check and lint (for CI)make test- RunClerkKitTestson macOSmake test-ui- RunClerkKitUITestson iOS Simulatormake test-e2e- Run E2EHost tests on iOS Simulatormake test-integration- Run only integration tests (requires.keys.jsonfile; Clerk employees only)make fetch-test-keys- Fetch integration test keys from 1Password (optional, for Clerk employees only; auto-installs CLI if needed)
This project uses SwiftFormat for code formatting. The configuration is stored in .swiftformat.
-
Pinned version:
0.60.0 -
Indentation: 2 spaces
-
Line length: 1000 characters (very permissive)
-
Line breaks: LF (Unix-style)
-
SwiftFormat parser version: 5.10
To ensure consistent indentation in Xcode, configure your editor to use 2 spaces:
- Open Xcode Preferences (⌘,)
- Go to Text Editing → Indentation
- Set Tab Width to
2 - Set Indent Width to
2 - Enable Tab Key: Inserts spaces, not tabs
- Enable Indent Using: Spaces
Note: SwiftFormat will automatically format your code on commit, but configuring Xcode ensures consistency while editing.
This project uses SwiftLint for code quality checks. The configuration is stored in .swiftlint.yml.
- Pinned version:
0.63.2
SwiftLint checks for:
- Code quality issues
- Style violations
- Potential bugs
- Best practices
This project uses Swift Testing for package unit and integration tests, and Maestro for app-level E2E UI automation. Tests are organized into three categories:
ClerkKitTests live in Tests/ and use mocked API responses via the Mocker library. ClerkKitUITests live in Tests/UI and run on an iOS Simulator.
Running unit tests:
make test # Run ClerkKitTests on macOS
make test-ui # Run ClerkKitUITests on iOS SimulatorWhen to run unit tests:
- Before committing any code changes
- During development for quick feedback
- When debugging specific functionality
Integration tests are located in Tests/Integration/ and make real API calls to Clerk instances. They verify end-to-end functionality and require network access.
Important: Integration tests can only be run locally by Clerk employees who have access to the 1Password Shared vault. They are not part of the regular pull request CI workflow and are executed in the maintainer-only Release SDK workflow.
Running integration tests (Clerk employees only):
make test-integration # Run only integration testsEach test method must call configureClerkForIntegrationTesting(keyName:) at the start to specify which key to use.
Requirements:
- Network access
- Valid Clerk test instance publishable key configured in
.keys.jsonfile - Test instance should be stable and not modified by other processes
- Clerk employees only: Access to Clerk's 1Password Shared vault
Setup (Clerk employees only):
- Run
make setupto create the.keys.jsonfile (if you haven't already) - Run
make fetch-test-keysto automatically populate.keys.jsonfrom 1Password- This will automatically install 1Password CLI if not already installed
- Requires access to Clerk's Shared vault and 1Password desktop app integration enabled
- See 1Password CLI setup guide
- If
make fetch-test-keysdoesn't work, you can manually add the key to.keys.json:{ "auth-email-code-password": { "pk": "pk_test_..." } }
OSS contributors:
- Integration tests are not run automatically for pull requests
- You don't need to configure anything locally
- The
.keys.jsonfile created bymake setupwill remain empty, which is expected
How it works:
- The
.keys.jsonfile is automatically created bymake setupwith blank baseline E2E key entries such asauth-email-code-password.pk,auth-legal-consent.pk,auth-multi-methods.pk,auth-phone-code.pk,auth-username-password-user-model.pk,session-task-setup-mfa.pk, andwith-email-codes.pk - Clerk employees can run
make fetch-test-keysto populate it from 1Password viascripts/fetch-1password-secrets.sh; fetched entries may include bothpkand optionalskvalues, such as reset-password fixtures, so do not stripskvalues from.keys.json - Each test method must call
configureClerkForIntegrationTesting(keyName:)with the desired key name at the start - Tests read keys directly from
.keys.jsonfile - In the maintainer-only Release SDK workflow, the
.keys.jsoncontent is provided viaCLERK_TEST_KEYS_JSONGitHub Actions secret (written to.keys.jsonbefore tests run)
Troubleshooting:
- If integration tests fail with network errors, check your internet connection
- If tests fail with authentication errors, verify the test instance publishable key in
.keys.jsonis valid - If
.keys.jsonfile is missing, runmake setupto create it - If
make fetch-test-keysfails, ensure you have 1Password CLI installed and authenticated with access to the Shared vault - Integration tests may be slower than unit tests due to real network calls
- Some tests may be flaky due to network conditions - consider retrying
E2E tests live in Examples/E2EHost/Maestro/ and run a dedicated SwiftUI test host app on an iOS Simulator. The host app exists only for release-gating E2E coverage, keeping product-facing examples such as Quickstart free of test-only controls and launch configuration. By default, make test-e2e runs the email-code sign-up flow with the auth-email-code-password mobile integration test instance.
Running E2E tests (Clerk employees only):
make fetch-test-keys
make test-e2eIf CI is missing a named test key, add it to the 1Password item, then sync the GitHub Actions snapshot:
make sync-test-keys-to-githubYou can also provide a key directly:
CLERK_E2E_PUBLISHABLE_KEY=pk_test_... make test-e2eTo run a different flow:
E2E_MAESTRO_FLOW_NAME=session-task-setup-mfa make test-e2eAvailable flow names are auth-email, auth-phone, user-profile, and session-task-setup-mfa. Each flow selects its required test instance automatically. CLERK_E2E_KEY_NAME can override that selection when necessary.
To choose a specific simulator:
IOS_SIMULATOR_DESTINATION='platform=iOS Simulator,name=iPhone 16' make test-e2eRequirements:
- Network access
maestro-runner- Valid publishable key in
.keys.jsonforCLERK_E2E_KEY_NAMEorCLERK_E2E_PUBLISHABLE_KEY - iOS Simulator available through
xcrun simctl
The test runner writes failure artifacts to build/reports/maestro-<flow>. CI uploads those reports when a flow fails. Generated tests must use the approved accessibility identifiers and be reviewed like production code.
SDK releases can be published through the Release SDK GitHub Actions workflow:
- Open Actions in GitHub and select Release SDK
- Click Run workflow
- Ensure the selected branch is
main - Provide the target SemVer version (for example
1.2.3)
The workflow automatically:
- Verifies the workflow actor has GitHub
maintainoradminpermission - Runs formatting, linting, unit tests, integration tests, and multi-platform builds in the
checksjob - Updates
Clerk.sdkVersioninSources/ClerkKit/Utils/Version.swiftin thepublishjob - Commits the version bump to
main - Creates and pushes tag
v<version>in thepublishjob - Publishes a GitHub Release with auto-generated release notes
Feel free to open an issue or reach out to the maintainers if you have questions about contributing!