Mode: tracker-authoritative. This guide belongs to the Atlassian journey
where Jira holds the team’s real backlog. If docs/product/ is canonical and
Jira is only for reporting, use repo-first projection
instead.
Use this when: Your Atlassian Data Center instance blocks personal access tokens and requires corporate SSO sign-in for Jira reads or Confluence space crawls.
Prerequisites: The jira or confluence-crawler skill installed; an enterprise-edited references/sso-config.toml pointing at your corporate instance.
Result: A registered SSO session in the broker’s secured store so both skills authenticate via captured web session instead of a token — and a jira.py check that re-establishes it, headlessly, when it expires.
Ask the agent to guide the user-run registration:
Help me register a read-only SSO web session for Jira and Confluence on our Data Center instance.On an Atlassian Data Center instance fronted by corporate SSO where personal
access tokens are blocked, jira
reads and confluence-crawler
can authenticate by a captured web session (a cookie jar) instead of a token. This
is the auth: sso-cookie path; both skills keep a creds (token)
fallback, so nothing changes for token users.
1. Pre-bake the instance config (once, per org)
Section titled “1. Pre-bake the instance config (once, per org)”Each skill ships references/sso-config.toml placeholder-shaped (auth_default = "creds", *.invalid hosts). An enterprise edits it to point at the corporate
instance and flips the default:
auth_default = "sso-cookie"
[sso]profile = "jira"base_url = "https://jira.corp.example.com" # https onlylogin_url = "https://sso.corp.example.com/login"success_url_pattern = "https://jira.corp.example.com/secure/Dashboard.jspa"cookie_domains = ["corp.example.com"] # the jar is confined to thesevalidation_endpoint = "/rest/api/2/myself" # root-relativeDistribute this as a pack customization so a developer installs the pack already pointed at your instance. The config carries no secrets — only connection parameters; the session cookie never lives here.
profile is confined to ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$ — it becomes a
filename and a keychain entry name — and Windows reserved device names (CON,
NUL, COM1…) are refused with or without an extension.
2. Register the session (once, per developer)
Section titled “2. Register the session (once, per developer)”python scripts/jira.py check --register # in the jira skill dirOne command: it captures the session and then runs the check. A browser opens for you to sign in, and the destination host is printed to stderr first.
Run this yourself. The agent will relay the command as text; it never invokes it. Everything after this is automatic.
Before opening anything, check --register asks your instance where it sends
users to sign in and compares that against login_url. On a mismatch it refuses
with both hosts named and no browser. It does not always verify. Where
login_url sits on the same host as base_url — SP-initiated SAML, which is
the majority Data Center configuration — the check short-circuits and confirms
nothing. Treat check --register as the best available first-run path, not as a
guarantee.
scripts/setup_sso.py remains, for exactly two cases:
- a scripted pre-bake, where an org registers profiles without a person present;
- when
check --registerrefuses because it cannot confirm the destination — a host mismatch you know to be correct, or a topology where nothing resolves.
It performs no destination check at all. It is safe only because you type it.
confluence-crawler registers through setup_sso.py. It has no
--register verb and no self-healing check yet; both skills share one broker
store, so registering the profile from either skill serves both. Registering via
jira.py check --register is the better route where the profile is shared.
Hardening: keeping the agent away from --register (Claude Code only)
Section titled “Hardening: keeping the agent away from --register (Claude Code only)”If you want belt as well as braces, a Claude Code user can add a deny rule in
~/.claude/settings.json — the user-scope file, not the repo’s:
{ "permissions": { "deny": ["Bash(python scripts/jira.py check --register*)"] } }It must live in your home directory because anything inside the repo
(.claude/settings.local.json) is a file the agent can edit.
This is belt, not a boundary. It reduces accidental invocation by an erring
agent. It does not put first capture out of an agent’s reach: an agent with
shell access can invoke ~/.agentbundle/bin/sso-broker.py register directly,
bypassing every command-level rule. Only privilege separation would support an
out-of-reach claim, and none ships today.
kiro-ide, codex, copilot, cursor and gemini have no equivalent
per-command control — they offer coarse sandbox levels or tool-name
allow-lists, not per-invocation rules. On those, the skill rules are the only
layer.
3. Use the skills normally
Section titled “3. Use the skills normally”python scripts/jira.py check # confirms the sessionpython scripts/jira.py search 'project = ABC' --limit 20python scripts/crawl_space.py --space ENGOn the cookie path the skill attaches the confined jar to its HTTP client, sends
no Authorization header, and honors your corporate proxy and CA bundle
(HTTPS_PROXY / NO_PROXY, SSL_CERT_FILE / REQUESTS_CA_BUNDLE). The session
cookie is a bearer secret — the skill resolves it through the broker and never
prints it.
check self-heals an expired session
Section titled “check self-heals an expired session”Your app session expires long before your corporate SSO session does. When it
has, jira.py check re-establishes it and retries, in the same command — no
second step and no browser: the recapture runs headless, and it takes no
sign-in destination, so nothing an agent does can steer where it goes.
Two cases where it stops instead:
| What happened | What you see |
|---|---|
| Your IdP session has expired too — typically first use of the day | exit 2 and a message naming check --register. No login page is opened. Run the command it names. |
| No session was ever captured on this machine | exit 2 naming the same command. |
Only check does this. Every other subcommand behaves exactly as before, and
check on the token path is unchanged.
--insecure is a global flag (jira.py --insecure check) and is inert on
the cookie path — the session cookie is a bearer secret, so TLS verification
stays on. check says so rather than letting you believe otherwise.
Upgrading a pre-baked config without losing your edits
Section titled “Upgrading a pre-baked config without losing your edits”references/sso-config.toml is upstream-owned but locally edited — exactly the
case the adapt-to-project class-2
.upstream companion merge handles. When a later catalogue release ships a new
upstream sso-config.toml, install writes it alongside yours as a .upstream
companion rather than clobbering your instance config; adapt-to-project then
walks you through merging any new upstream keys into your edited file. So an
org’s pre-baked config survives upgrades — you reconcile new connection-param
keys deliberately, you don’t lose them.
What you have now
Section titled “What you have now”You have a registered SSO profile in the broker’s secured store and a successful connectivity check for the configured Atlassian instance. The cookie path is read-only: use it for Jira reads and Confluence crawls, and run the named registration command yourself when an expired identity-provider session needs a browser.