stack/sdks/implementations/swift/Tests/StackAuthTests/TestConfig.swift
Konsti Wohlwend 8052a2be62
Some checks failed
all-good: Did all the other checks pass? / all-good (push) Has been cancelled
Ensure Prisma migrations are in sync with the schema / check_prisma_migrations (22.x) (push) Has been cancelled
DB migration compat / Check if migrations changed (push) Has been cancelled
Docker Server Build and Push / Docker Build and Push Server (push) Has been cancelled
Docker Server Build and Run / docker (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (mock, 22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (prod, 22.x) (push) Has been cancelled
Runs E2E API Tests with custom port prefix / build (22.x) (push) Has been cancelled
Lint & build / lint_and_build (latest) (push) Has been cancelled
Dev Environment Test With Custom Base Port / restart-dev-and-test-with-custom-base-port (push) Has been cancelled
Dev Environment Test / restart-dev-and-test (push) Has been cancelled
Run setup tests with custom base port / setup-tests-with-custom-base-port (push) Has been cancelled
Run setup tests / setup-tests (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
DB migration compat / No migration changes (skipped) (push) Has been cancelled
"Require publishable client key" toggle (#1158)
<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md

-->

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Touches authentication and OAuth token/authorize flows and changes how
client requests are validated, so regressions could cause widespread
login/client-access failures. Also includes a data migration that alters
effective security posture for existing projects.
> 
> **Overview**
> Adds a **project-level toggle**
(`project.requirePublishableClientKey`) to control whether client
requests/OAuth flows must include a publishable client key, including a
DB migration that backfills existing projects to require it.
> 
> Backend auth now treats the publishable client key as *optional when
allowed*, introducing a public sentinel (`__stack_public_client__`) and
returning a new specific error
(`PUBLISHABLE_CLIENT_KEY_REQUIRED_FOR_PROJECT`) across smart request
auth + OAuth `authorize`/`callback`/`token` endpoints.
> 
> Dashboard and SDKs update key generation/display and request
construction to handle missing publishable keys, expose an advanced
toggle on the Project Keys page, and extend internal config overrides to
support a new `project` level; E2E/tests and schema fuzzing are expanded
accordingly, and CI adds a forward-compat migration check job when
back-compat fails.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5d06c08613. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Project-level config to require publishable client keys; migration
applied to existing projects.

* **Improvements**
* Auth flows now support optional publishable client keys with explicit
validation and a sentinel for keyless OAuth.
* Dashboard/UI and SDKs handle publishable keys as optional and
conditionally show/generate them.
  * Admin/client APIs extended to manage project-level overrides.

* **Bug Fixes**
  * Key validation behavior aligned with project config.

* **Tests**
* Expanded E2E and unit tests covering optional/required publishable-key
scenarios.

* **Documentation**
* Spec and knowledge docs updated to describe the sentinel and config
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-19 10:23:16 -08:00

90 lines
3.3 KiB
Swift

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
@testable import StackAuth
/// Shared test configuration
/// Set environment variables to customize test behavior:
/// - NEXT_PUBLIC_STACK_PORT_PREFIX: Port prefix for backend (default: "81")
/// - STACK_SKIP_E2E_TESTS: Set to "true" to skip E2E tests
struct TestConfig {
static let portPrefix = ProcessInfo.processInfo.environment["NEXT_PUBLIC_STACK_PORT_PREFIX"] ?? "81"
static let baseUrl = "http://localhost:\(portPrefix)02"
static let skipE2E = ProcessInfo.processInfo.environment["STACK_SKIP_E2E_TESTS"] == "true"
// Test credentials - these should match the test project in the backend
// See apps/e2e/.env.development for the source of truth
static let projectId = "internal"
static let publishableClientKey = "this-publishable-client-key-is-for-local-development-only"
static let secretServerKey = "this-secret-server-key-is-for-local-development-only"
/// Check if backend is accessible
static func isBackendAvailable() async -> Bool {
guard !skipE2E else { return false }
guard let url = URL(string: "\(baseUrl)/api/v1/health") else { return false }
do {
let (_, response) = try await URLSession.shared.data(from: url)
if let httpResponse = response as? HTTPURLResponse {
return (200..<300).contains(httpResponse.statusCode)
}
return false
} catch {
return false
}
}
/// Generate a unique test email
static func uniqueEmail() -> String {
"test-\(UUID().uuidString.lowercased())@example.com"
}
/// Generate a unique team name
static func uniqueTeamName() -> String {
"Test Team \(UUID().uuidString.prefix(8))"
}
/// Create a new client app instance for testing.
/// By default uses a fresh isolated MemoryTokenStore (not from the registry)
/// to avoid interference between parallel tests.
static func createClientApp(
tokenStore: TokenStoreInit? = nil,
publishableClientKey: String? = TestConfig.publishableClientKey
) -> StackClientApp {
// Default to a fresh isolated memory store, not the shared registry singleton
let store = tokenStore ?? .custom(MemoryTokenStore())
return StackClientApp(
projectId: projectId,
publishableClientKey: publishableClientKey,
baseUrl: baseUrl,
tokenStore: store,
noAutomaticPrefetch: true
)
}
/// Create a new server app instance for testing
static func createServerApp() -> StackServerApp {
StackServerApp(
projectId: projectId,
publishableClientKey: publishableClientKey,
secretServerKey: secretServerKey,
baseUrl: baseUrl
)
}
/// Standard test password that meets requirements
static let testPassword = "TestPassword123!"
/// Weak password that should be rejected
static let weakPassword = "123"
}
// MARK: - Convenience Aliases
let baseUrl = TestConfig.baseUrl
let testProjectId = TestConfig.projectId
let testPublishableClientKey = TestConfig.publishableClientKey
let testSecretServerKey = TestConfig.secretServerKey