Where Jira time trackers store credentials: API tokens and OAuth

A security review of how Tempo, Clockwork, Everhour, Clockify, and Planim Time handle Jira API tokens, OAuth credentials, Marketplace access, and revocation.

A Jira tracker can authenticate through a Marketplace app, Atlassian OAuth, or a user-supplied API token. Those models expose different systems and revoke differently. Atlassian’s token management docs treat an API token as a personal credential, while OAuth uses an explicit app consent. The useful security question is no longer just “where did the pasted token go?” It is “which long-lived credential exists, who can use it, and which infrastructure sees it during sign-in and sync?”

We built one of the trackers in this list, Planim Time, around device-held long-lived credentials. Version 0.4 added Sign in with Atlassian as the default while keeping API-token auth as a local fallback. The goal here is to put the actual auth model each tracker uses on the table, including the short-lived broker involved in our OAuth flow, so the trade-offs are visible.

The threat model, in one paragraph

A Jira API token is a bearer credential: anyone holding the cleartext can act as you against the Jira REST API. The interesting question for any tracker isn’t “is the token encrypted?” It always is, in transit and at rest. The interesting question is who else holds the cleartext, and under what circumstances does it become reachable? A token in your OS keychain is reachable to processes running as you, on this machine. A token in a vendor’s cloud is reachable to that vendor’s infrastructure, their on-call engineers, anyone who breaches them, and any subpoena that lands on their doorstep. Both are defensible designs. They just have very different blast radii.

Four auth models in this category

Every Jira time tracker authenticates with Jira using one of four shapes:

1. Atlassian Marketplace app (Connect or Forge). A Jira admin installs the app into the tenant, but the two frameworks have different trust boundaries. A Connect app exchanges an installation secret and typically authenticates from vendor infrastructure with signed JWTs. A Forge app runs in Atlassian’s isolated runtime, uses declared scopes and platform-managed API access, and can only reach external domains allowed by its manifest. Forge Remotes can still involve vendor infrastructure, so “Marketplace app” alone does not tell you where every component or credential lives.

2. Atlassian OAuth 3LO. The user approves an app in Atlassian’s browser flow. The app receives scoped access and refresh credentials instead of a manually copied API token. A web app normally stores those credentials on its backend. A desktop app can keep them in the OS keychain, although it may still use a backend broker for the confidential code exchange or token refresh.

3. User-supplied API token, vendor-stored. The user generates a personal Atlassian API token, pastes it into a vendor signup form, and the vendor uses it to call Jira on the user’s behalf. The token sits in the vendor’s database, encrypted at rest.

4. User-supplied API token, locally stored. The user pastes a token into a desktop app, and the app saves it to the OS credential vault: Keychain on macOS, Credential Manager on Windows, Secret Service on Linux. The vendor’s servers never see the token.

Each model trades a different thing. Marketplace apps centralise install and revoke through Jira, but Connect and Forge do not share one credential architecture. OAuth provides scoped consent but may introduce a token broker or vendor credential store. Vendor-stored API tokens expand the vendor’s breach surface. Locally stored tokens reduce that surface but are per-machine by design.

Tempo Timesheets

Tempo Timesheets is a Marketplace plugin that is actively migrating from Connect to Forge. The rollout is gradual, so a tenant can still be on the legacy Connect version or already on Forge. A Jira admin installs the app and users do not paste a Jira API token for the core integration, but the exact runtime and authentication boundary now depends on the installed app version.

Tempo also issues its own personal API tokens for Tempo’s REST APIs. These are separate from Jira tokens and only authenticate calls to Tempo, not to Jira. They’re shown once and stored on Tempo’s side. There’s a known administrative gap here: only the user who created a Tempo API key can view or revoke it, which becomes uncomfortable during offboarding. If a developer leaves and IT doesn’t think to ask them to revoke their Tempo key first, that key can outlive their employment. Tempo’s product team has acknowledged the request for centralised admin; check the linked idea for current status.

Where the credential state lives: the Atlassian platform and, depending on the installed Connect/Forge architecture, Tempo infrastructure. For Tempo API users, Tempo’s own API token remains a separate Tempo-side credential.

Clockwork (HeroCoders)

Clockwork is a Marketplace plugin installed and authorised by a Jira admin. HeroCoders completed Clockwork’s move to Forge in March 2026. Forge puts the app inside Atlassian’s runtime and platform-managed authorization model, though that does not automatically mean every component and stored record stays within Atlassian: HeroCoders says Clockwork does not yet carry the stricter Runs on Atlassian badge. HeroCoders is also a Cloud Fortified vendor.

Clockwork also publishes its own REST API with user-generated API tokens, used for scripting against Clockwork itself. Same shape as Tempo: tokens issued in Clockwork’s UI, stored in HeroCoders’ backend, scoped to that user’s Jira permissions.

Where the credential state lives: Atlassian’s Forge authorization and runtime, plus the Clockwork service where its architecture uses vendor infrastructure. Clockwork’s own user-generated API tokens are separate credentials managed by HeroCoders.

Everhour

Everhour is a hybrid: a Marketplace add-on that surfaces the timer inside Jira, plus an Everhour cloud account that holds time data, projects, budgets, and integrations. The Jira side uses the Marketplace install path; the Everhour side requires an Everhour account. With worklog sync enabled, Everhour entries are written to native Jira worklogs and later edits to those linked worklogs can flow back to Everhour. Historical worklogs and new entries created directly in Jira are not imported into Everhour, so this is not a complete two-way mirror.

If you also use Everhour for non-Jira tools (GitHub, Trello, Asana, etc.), each of those integrations stores its credentials in your Everhour cloud account. None of those credentials live on your machine.

Where the credential and integration state lives: Atlassian’s tenant (Marketplace install) + Everhour’s backend (Everhour account, integration state, and any non-Jira integration credentials).

Clockify

Clockify’s current Jira Cloud integration is a free Atlassian Marketplace app. A Jira admin installs it and each user connects a Clockify account. Clockify documents two-way sync between Jira worklogs and Clockify entries. That Cloud path should not be described as “paste a personal Jira API token into Clockify”; the relevant trust boundary is the Marketplace app plus Clockify’s cloud account and integration state.

Clockify’s own API uses an X-Api-Key HTTP header containing a key generated in your Clockify profile. That key authenticates against Clockify, not Jira; same storage location.

Where the cleartext lives: no user-supplied Jira API token in the documented Jira Cloud path; Atlassian Marketplace authorization and Clockify account/integration credentials span Atlassian and Clockify infrastructure. Clockify API keys remain separate Clockify credentials.

Planim Time

Planim Time is a native desktop app for macOS, Windows, and Linux. Sign in with Atlassian is the default. Long-lived OAuth access and refresh credentials are stored in the OS keychain. A short-lived backend broker handles the OAuth code exchange and refresh response, then passes the result to the app; it does not remain the long-term token store. The optional API-token fallback is simpler: that Jira token never leaves the machine.

The local storage implementation is small enough to print:

use keyring::Entry;

const SERVICE: &str = "planim-time-tracker";

pub fn set_secret(key: &str, value: &str) -> Result<(), String> {
    Entry::new(SERVICE, key)
        .map_err(|e| format!("Keyring entry error: {e}"))?
        .set_password(value)
        .map_err(|e| format!("Failed to save to keyring: {e}"))
}

pub fn get_secret(key: &str) -> Result<Option<String>, String> {
    match Entry::new(SERVICE, key)
        .map_err(|e| format!("Keyring entry error: {e}"))?
        .get_password()
    {
        Ok(v) => Ok(Some(v)),
        Err(keyring::Error::NoEntry) => Ok(None),
        Err(e) => Err(format!("Failed to read from keyring: {e}")),
    }
}

That’s the entire storage layer. The keyring crate wraps three platform APIs:

  • macOS: Keychain Services, the same vault Safari uses for saved passwords
  • Windows: Credential Manager, accessed via the Win32 Credential Vault APIs
  • Linux: Secret Service over D-Bus, which is what GNOME Keyring and KWallet implement

For OAuth, the broker sees token material transiently during sign-in and refresh, while the desktop app holds the long-lived copy in the keychain and talks to Jira directly. For the API-token fallback, our backend never sees the Jira token at all. License checks are a separate flow. Credentials can be removed from the app or the system vault. For example, on macOS:

security find-generic-password -s planim-time-tracker
security delete-generic-password -s planim-time-tracker

I wrote a longer technical post on the implementation if you want the rationale at code-review depth.

Where the cleartext lives: long-lived copy in the OS keychain; OAuth broker memory and short-lived handshake state during exchange/refresh; API-token fallback only in the OS keychain.

Quick comparison

TrackerAuth model for JiraWhere cleartext livesAdmin revoke
Tempo TimesheetsConnect or Forge, depending on rollout stateAtlassian platform + Tempo infrastructure, boundary depends on installed versionJira admin for the app; user only for Tempo API tokens
ClockworkAtlassian ForgeAtlassian runtime + Clockwork serviceJira admin (Forge); user only (Clockwork API)
EverhourMarketplace install + Everhour accountAtlassian tenant + Everhour backendJira admin + Everhour admin
ClockifyMarketplace app + Clockify account (Jira Cloud)Atlassian + Clockify integration infrastructureJira admin / Clockify admin and user disconnect controls
Planim TimeAtlassian OAuth 3LO; local API-token fallbackOS keychain long-term; OAuth broker transientlyAtlassian app revoke or local delete; token revoke for fallback

What your IT team should ask

When the security review form lands on someone’s desk, the questions worth asking are concrete, not generic:

  • Where, exactly, is the cleartext credential stored? “Encrypted at rest” is necessary but not interesting; you want a name (vendor backend / Atlassian tenant / OS keychain).
  • Who can revoke it without involving the user? A token only the original user can revoke is a problem at offboarding.
  • What happens if the vendor is breached? Map your token’s blast radius the same way you’d map any other credential.
  • Does the vendor decrypt the token in the request lifecycle? Some vendors decrypt server-side to make the API call; others act as opaque proxies. The first model means cleartext is reachable to vendor on-call engineers.
  • Is the integration Cloud Fortified or Forge-published? For Marketplace plugins this is the closest thing to a default certification.

What we ended up choosing, and why

Picking the OS keychain as the long-term store means accepting a few constraints. Credentials are per-machine, so a laptop and desktop each need a sign-in. There is no Planim admin panel holding Jira refresh tokens for the whole team. OAuth makes onboarding easier than the old paste-token path while preserving device-held long-lived credentials.

What we got back: our database, backups, and support tooling are not the long-term store for Jira credentials. The important qualification is that the OAuth broker handles token material transiently during exchange and refresh. For teams whose review asks “does the vendor retain our Jira credentials?” the answer is no; for “does vendor infrastructure ever process OAuth tokens?” the answer is yes, briefly and for that purpose.

That trade-off only makes sense for a desktop-first product. If we’d built a web dashboard, we couldn’t have made it; the auth model and the product shape are the same decision. We wrote separately about why we shipped a desktop binary instead of a Marketplace plugin; this is the half of the rationale that lives in your security questionnaire.

If the storage side matters to your team, download Planim Time, sign in to a test site, and inspect Keychain Access on macOS (or Credential Manager on Windows, or seahorse on Linux). You will see the long-lived credential entry under planim-time-tracker; the security review should record the transient OAuth broker separately.

Frequently asked questions

Is it safe to give a time tracker my Jira API token?
A Jira API token is a bearer credential: anyone holding the cleartext can act as you against the Jira REST API. Whether handing it to a tracker is safe depends on where the cleartext lives afterwards. A token in your OS keychain is reachable only to processes running as you on that machine; a token in a vendor's cloud is reachable to their infrastructure, their on-call engineers, and anyone who breaches them. Both designs can be defensible, but the blast radii are very different.
Where should a Jira API token be stored?
For a desktop tracker, an API token should normally live in the operating system's credential vault: Keychain on macOS, Credential Manager on Windows, or Secret Service on Linux. OAuth changes the question: ask where long-lived access and refresh credentials are stored, whether a backend broker sees them during exchange or refresh, and whether it retains them. Planim stores long-lived credentials in the OS keychain; its API-token fallback never leaves the device.
Is Atlassian OAuth safer than pasting an API token?
OAuth usually improves consent and revocation because the user approves an app and can disconnect it without rotating a general API token. It does not eliminate trust boundaries. A desktop OAuth flow may use a backend broker during code exchange and refresh, so the review should ask whether that broker stores refresh tokens or only handles them transiently.
Can I revoke a Jira API token?
Yes. Atlassian treats API tokens as personal credentials: you create and revoke them from your Atlassian account's security settings, and revoking one immediately cuts off every tool that was using it. Watch out for vendor-side tokens, though. Tempo's own API keys, for example, can currently only be viewed and revoked by the user who created them, which becomes a gap during offboarding.
Do Marketplace plugins like Tempo see my Jira API token?
Not for the core Marketplace integration: you do not paste a personal Jira API token into Tempo. The exact trust boundary depends on the installed architecture. Connect uses a tenant installation secret and signed JWTs with vendor infrastructure; Forge uses platform-managed authorization in Atlassian's runtime and may still call declared vendor remotes. Tempo's staged Connect-to-Forge rollout means a tenant can currently be on either model.
What should a security review ask a Jira time tracker vendor?
Ask where exactly the cleartext credential is stored (vendor backend, Atlassian tenant, or OS keychain), who can revoke it without involving the user, and what the blast radius is if the vendor is breached. Also ask whether the vendor decrypts the token during the request lifecycle, and whether the Marketplace app is Cloud Fortified or Forge-published. Concrete names beat 'encrypted at rest' every time.