Getting Started with Cedarling Swift#
Installation#
Prerequisites#
- Xcode 14 or later
- iOS 14+ deployment target
Using pre-built release assets#
The recommended way to use Cedarling in an iOS app is via the pre-built XCFramework published with each Janssen release. This avoids having to install Rust or build the native library yourself.
Go to the Janssen releases page and download the following two files for your target version:
| File | Purpose |
|---|---|
cedarling_uniffi-ios-{version}.zip |
XCFramework containing Cedarling compiled for device and simulator |
cedarling_uniffi.swift |
UniFFI-generated Swift source that exposes the Rust API |
Unzip cedarling_uniffi-ios-{version}.zip to get Cedarling.xcframework.
For the latest stable version see the Janssen releases page.
Add to Xcode (manual)#
- Open your project in Xcode and click the project name at the top of the file navigator.
- Select your app target under Targets and open the General tab.
- Scroll down to Frameworks, Libraries, and Embedded Content.
- Drag
Cedarling.xcframeworkinto the list and set the embed option to Do Not Embed (it is a static library — embedding will cause a codesigning error). - Drag
cedarling_uniffi.swiftinto your source group, ensuring Add to target is checked. - Press ⌘B to verify the build.
Building from Source#
Refer to the iOS build guide for steps to build the XCFramework from source using Rust and Xcode.
Usage#
Initialization#
Initialize Cedarling with a JSON bootstrap configuration before making any authorization calls.
import CedarlingFFI
/*
* In a production environment, the bootstrap configuration should not be hardcoded.
* Instead, load it dynamically from environment variables, a remote URL,
* or a bundled configuration file.
*/
let bootstrapJson = """
{
"CEDARLING_APPLICATION_NAME": "MyApp",
"CEDARLING_LOG_LEVEL": "INFO",
"CEDARLING_LOG_TYPE": "std_out",
"CEDARLING_POLICY_STORE_LOCAL_FN": "/path/to/policy-store.cjar"
}
"""
guard let adapter = try? CedarlingAdapter(config: bootstrapJson) else {
print("Unable to initialize Cedarling")
return
}
Or with explicit error handling:
do {
let adapter = try CedarlingAdapter(config: bootstrapJson)
} catch let error as CedarlingException {
print("Unable to initialize Cedarling: \(error.message)")
} catch {
print("Unable to initialize Cedarling: \(error)")
}
Policy Store Sources#
Swift bindings support all native policy store source types. See Cedarling Properties for the full list of configuration options and Policy Store Formats for format details.
Example configurations:
// Load from a directory
let bootstrapJson = """
{
"CEDARLING_APPLICATION_NAME": "MyApp",
"CEDARLING_POLICY_STORE_LOCAL_FN": "/path/to/policy-store/"
}
"""
// Load from a local .cjar archive (Cedar Archive)
let bootstrapJson = """
{
"CEDARLING_APPLICATION_NAME": "MyApp",
"CEDARLING_POLICY_STORE_LOCAL_FN": "/path/to/policy-store.cjar"
}
"""
// Load from a remote .cjar archive (Cedar Archive)
let bootstrapJson = """
{
"CEDARLING_APPLICATION_NAME": "MyApp",
"CEDARLING_POLICY_STORE_URI": "https://example.com/policy-store.cjar"
}
"""
See Policy Store Formats for more details.
Authorization#
Cedarling provides authorization interfaces for evaluating access requests based on a principal (entity), action, resource, and context.
- Token-Based Authorization is the standard method where principals are extracted from JSON Web Tokens (JWTs), typically used in scenarios where you have existing user authentication and authorization data encapsulated in tokens.
- Unsigned Authorization allows you to pass principals directly without JWTs. This is useful when you need to authorize based on internal application data.
Token-Based Authorization (Multi-Issuer)#
For token-based authorization, use authorizeMultiIssuer which processes JWT tokens and maps them to Cedar entities based on the token_metadata configuration in your policy store.
1. Prepare tokens
Tokens are provided as a [String: String] dictionary with token type as key and its JWT value:
let tokens: [String: String] = [
"Jans::Access_token": "<access_token_jwt>",
"Jans::id_token": "<id_token_jwt>",
"Jans::Userinfo_token": "<userinfo_token_jwt>"
]
2. Define the resource
let resource = """
{
"cedar_entity_mapping": {
"entity_type": "Jans::Application",
"id": "app_id_001"
},
"name": "App Name",
"url": {
"host": "example.com",
"path": "/admin-dashboard",
"protocol": "https"
}
}
"""
3. Define the action
let action = #"Jans::Action::"Read""#
4. Define context (optional)
let context = "{}"
5. Authorize
do {
let result = try adapter.authorizeMultiIssuer(
tokens: tokens,
action: action,
resource: resource,
context: context
)
if result.decision {
print("Access granted")
} else {
print("Access denied")
}
} catch {
print("Authorization error: \(error)")
}
See Multi-Issuer Authorization for more details.
Unsigned Authorization#
For unsigned authorization, use authorizeUnsigned (JSON principal string, nullable for no asserted principal) or authorizeUnsignedEntity (optional EntityData) directly without JWTs.
1. Define the resource
This represents the resource that the action will be performed on, such as a protected API endpoint or file.
let resource = """
{
"cedar_entity_mapping": {
"entity_type": "Jans::Issue",
"id": "admin_ui_id"
},
"name": "App Name",
"permission": "view_clients"
}
"""
2. Define the action
An action represents what the principal is trying to do to the resource — for example, read, write, or delete.
let action = #"Jans::Action::"Update""#
3. Define context
The context represents additional data that may affect the authorization decision.
let context = "{}"
4. Define the principal (optional)
let principalJson = """
{
"cedar_entity_mapping": {
"entity_type": "Jans::Workload",
"id": "workload_123"
},
"client_id": "my_client"
}
"""
let principal = EntityData.fromJson(principalJson)
5. Authorize
do {
let result = try adapter.authorizeUnsignedEntity(
principal: principal,
action: action,
resource: resource,
context: context
)
if result.decision {
print("Access granted")
} else {
print("Access denied")
}
} catch {
print("Authorization error: \(error)")
}
Logging#
Retrieve logs using the popLogs function and related helpers.
// Get all logs and clear the buffer
let logs: [String] = adapter.popLogs()
// Get all log IDs (does not clear the buffer)
let logIds: [String] = adapter.logIds
// Get a specific log entry by ID
if let firstId = logIds.first {
let logEntry: String = adapter.getLogById(id: firstId)
print(logEntry)
}
// Get logs filtered by tag (e.g., "System")
let systemLogs: [String] = adapter.getLogsByTag(tag: "System")
To use the log functions, set the bootstrap properties, CEDARLING_LOG_TYPE to memory and configure CEDARLING_LOG_TTL with an appropriate value (in seconds). See the Log behavior documentation to learn about other log-related bootstrap properties.