Skip to main content
Migrate Already selling? Move your customers to Keylight without re-issuing a single key.
Keylight
Blog
macos keychain license-keys

How to Store a Signed License Token in the macOS Keychain

2 min read Nicolas Demanez — Founder

For a directly sold Mac app, the signed license token should usually live in the macOS Keychain. The token is what your app reads on launch to decide whether the customer is licensed, and the Keychain is the safest default place to keep it. This fits into the broader flow described in how to license a macOS app outside the App Store.

What the signed license token is

A signed license token is not just the text the customer typed into an activation window. It is the server’s answer after activation: a signed entitlement that says this customer, product, plan, device, expiry, and revocation state are valid.

Because the token is signed, your app can verify it locally. The customer can read the token, but they cannot change expiresAt, activationLimit, revoked, or plan without breaking the signature.

That signature gives you tamper resistance. Storage still matters because storage affects how easy the token is to copy, delete, or lose.

Why Keychain is the best default

The macOS Keychain is designed for sensitive app data. It is encrypted, access-controlled, and separate from your app bundle. It also survives ordinary app updates and reinstalls, which prevents a common support problem: “I reinstalled and lost my license.”

For licensing, a simple rule works well:

  • store the signed license token in Keychain;
  • store non-sensitive refresh metadata in Application Support or UserDefaults;
  • never store Stripe secrets or signing private keys in the app;
  • verify the token signature locally on launch.

The longer storage comparison is in where to store license data on macOS.

What belongs outside Keychain

Not every licensing value needs Keychain. A timestamp like nextRefreshAt is not sensitive. A UI flag like hasSeenActivationHelp is not sensitive. A log saying the last refresh failed with a network timeout is not sensitive.

Those values can live in Application Support or UserDefaults. Keeping them outside Keychain makes the app easier to debug and avoids treating ordinary cache data like a secret.

The signed license token is different. If copying the value to another Mac could help someone bypass activation limits, keep it in Keychain.

Minimal Swift shape

Real Keychain wrappers are a little verbose, but the app-side shape is small:

struct StoredLicense {
    let signedToken: String
    let nextRefreshAt: Date
}

func saveActivatedLicense(_ token: String) throws {
    try Keychain.save(
        service: "dev.keylight.example",
        account: "signed-license-token",
        value: token
    )
}

func checkLicenseOnLaunch() -> Bool {
    guard let token = try? Keychain.read(
        service: "dev.keylight.example",
        account: "signed-license-token"
    ) else {
        return false
    }

    return LicenseVerifier.verifySignedTokenLocally(token)
}

The exact wrapper can vary. The important pieces do not: save the signed token after activation, read it on launch, verify the signature locally, and refresh with the server periodically.

Where Keylight fits

Keylight’s SDK handles this storage detail for you. The app activates a license key, receives a signed lease, stores the offline-ready license data, and exposes a license state your UI can read.

If you are implementing this yourself, pair this post with offline license validation, adding license keys to a Swift macOS app, and device activations. If you prefer not to maintain Keychain edge cases, Keylight owns the storage and refresh flow.

Frequently asked

Should a Mac app store a signed license token in the Keychain?+

Yes. The Keychain is the best default for the signed license token or activation credential because it is protected by macOS and survives app updates and reinstalls.

Can a signed license token be stored in Application Support?+

It can, because the signature prevents tampering, but it is easier to copy. Application Support is better for non-sensitive cache data such as refresh timestamps.

Does Keychain storage replace offline validation?+

No. The Keychain stores the token. Offline validation is the separate step where the app verifies the token signature locally with a public key.

Ready to ship?

Create your account and start licensing your apps in under a minute. Free forever tier included.

Start Free