Zum Inhalt springen

Browser sign-in

How codecharter login signs a developer machine in through the browser, what a device token is, and how logout works.

codecharter login signs a single machine in to the portal using your normal browser session. It is the convenient way to license a developer workstation: no API key to copy around, no license file to download by hand. The machine receives a device token that can do exactly one thing, renew a short-lived license for your account, and that you can revoke at any time from the portal.

For CI and other headless environments an API key remains the right credential. Which one applies where is covered under Credentials and precedence.

Signing in

Run the command on the machine you want to sign in:

codecharter login

The CLI starts a sign-in with the portal and opens your default browser on the verification page. It also prints the page and the code, so an SSH session or a machine without a desktop works just as well:

Your browser has been opened to complete the sign-in.

    https://codecharter.tools/activate
    Code: 7QRX-4KTB

If no browser could be opened, the first line reads "Open this page in a browser to complete the sign-in:" instead, and you open the printed page yourself, from any device. The browser you confirm in does not have to be on the machine that is signing in.

The code is eight characters in two groups of four. It only uses digits 2-9 and capital letters without I and O, so there is nothing to confuse when you read it off one screen and type it into another. It is valid for ten minutes; after that the sign-in has to be started again.

While you confirm, the CLI keeps checking with the portal and prints Waiting for you to confirm the code....

Confirming in the browser

The verification page is /activate and requires you to be signed in to the portal. If you are not, you land on the normal login page first and are taken back afterwards. When the browser was opened by the CLI the code is already filled in; you always get to see it and have to confirm it explicitly.

The page shows two things before you decide:

  • Device, how the machine identifies itself. The CLI sends CodeCharter CLI on <machine name>.
  • Code, so you can compare it with what your terminal printed.

Compare both. If a code was sent to you by someone else, do not approve it: approving grants that machine the right to renew a license for your account until you revoke it. Choose Approve to complete the sign-in, or Reject to refuse it.

After confirming

Once you approve, the CLI stores the credentials and finishes:

Signed in. The device token and license are stored on this machine.

The command exits with code 0. Every gated command now works on this machine without further configuration, and the license is renewed automatically from the stored device token as it nears expiry.

If you reject the sign-in, the CLI prints Sign-in was denied in the browser. and exits with code 1. If the ten minutes run out, it prints The code expired before it was confirmed. Run 'codecharter login' again. and also exits with code 1. If your subscription lapsed between approving and the next poll, it prints Your account has no active subscription. Visit the portal to start a trial or subscribe. and stops there rather than waiting the code out. Subscribe in the portal, then run codecharter login again — it issues a fresh code for you to approve.

What is stored, and where

Two files are written into your per-user config directory, the same location the license cache already uses:

File Contents
codecharter.device-token The device token for this machine
codecharter.license The short-lived license issued along with it

The directory is $XDG_CONFIG_HOME/codecharter on Linux and macOS, %APPDATA%\CodeCharter on Windows, with $HOME/.config/codecharter as the fallback on Unix systems without XDG_CONFIG_HOME. On Unix the token file is created with owner-only permissions, so it is never briefly readable by other accounts on the machine.

If the CLI cannot determine a per-user config directory, it reports "signed in, but no per-user config directory was found to store the credentials" and exits with code 1. Nothing is stored in that case, so simply run the command again once one of the directories above is available.

What a device token can do

A device token starts with cgd_ and has exactly one permission: minting a short-lived license for your account. That is the whole scope.

  • It cannot read or change your rules, profiles, or drafts.
  • It cannot download CLI archives or publish checks.
  • Every portal endpoint other than license renewal rejects it with 403 Forbidden, regardless of what your account is otherwise allowed to do.

This is the practical difference to an API key, which carries read:rules and optionally write:rules. A leaked device token cannot be used to read your rule content, and it cannot be used to push anything.

The token itself has no expiry date. It stays valid until you revoke it in the portal, which is why the portal lists every signed-in machine for you, see Authorized devices.

Which account a machine is signed in as

A machine is signed in as whoever confirms the code in the browser, and the license it renews is that account's. That account needs an active subscription. If it has none, the approval page says so instead of accepting the confirmation, and your code stays valid — start a trial or subscribe, then approve the same code, as long as the ten minutes have not run out. Rejecting a device you do not recognize works whatever your subscription says.

So browser sign-in covers your own machines, not your colleagues'. The portal uses a single-account model, so for a team the license file remains the way to license everybody else, see Rolling out CodeCharter to your team. Signing a machine in does not consume or assign a seat; seats are counted per developer, not per device entry.

Checking the current state

codecharter auth status reports which credential this machine would authenticate with, without ever printing the credential itself:

Portal:      https://codecharter.tools
Credential:  device token (/home/you/.config/codecharter/codecharter.device-token)
License:     valid, plan Team, expires 2026-08-01 09:14:22Z

The Credential line reads API key from CODECHARTER_API_KEY when the environment variable is set, device token (<path>) when this machine is signed in, and none - run 'codecharter login', or set CODECHARTER_API_KEY when neither is available.

Because neither the key nor the token is printed, the output is safe to paste into a support request. Add --json for a machine-readable object with the fields portal_url, credential (api_key, device_token, or none), device_token_path, and a license object carrying valid, plan, expires_at, and message. The command is not license-gated and always exits with code 0.

Signing out

codecharter logout

This removes the stored device token from this machine:

Signed out. The stored device token was removed from this machine.
The cached license is left in place and will simply expire; it is no longer renewed from here.

Two things are worth being precise about here.

Logout is local. It removes the token from this machine but does not invalidate it in the portal. To lock a machine out for good, for example because you no longer have access to it, revoke the device in the portal instead, see Authorized devices.

The cached license is deliberately kept. It may have come from an API key or from an installer rather than from a browser sign-in, so deleting it would break setups that logout never touched. It is short-lived and, with the token gone, nothing renews it any more.

If no token was stored, the command reports "Not signed in on this machine; there was no stored device token to remove." Either way it exits with code 0, so you can run it in a cleanup script without special-casing.

Options

Option Command Effect
--portal-url <url> login Sign in to a different portal instead of the configured one
--json login Emit the sign-in as newline-delimited JSON events
--json auth status Emit machine-readable JSON instead of text
--license <path> auth status Inspect a specific license file instead of the standard search path

login, logout, and auth status are not license-gated. They are how a machine obtains a license in the first place, so requiring one would be circular.

Without --portal-url, login uses the CODECHARTER_PORTAL_URL environment variable if it is set, and the configured portal otherwise. Only https URLs are accepted, plus http to loopback for local development.

Scripting the sign-in

codecharter login --json writes one JSON object per line to standard output so an editor extension or script can follow the sign-in without parsing prose:

{"event":"code","verification_uri":"https://codecharter.tools/activate","user_code":"7QRX-4KTB"}
{"event":"status","status":"pending"}
{"event":"status","status":"success"}

The status vocabulary is pending, success, denied, expired, and subscription_required. The last one ends the sign-in the moment the portal reports it, rather than letting the code run out. Failures are written to standard error as {"event":"error","message":"..."}, so the event stream on standard output stays clean.

Troubleshooting

The browser opens but the code is not accepted

Codes are valid for ten minutes. If the terminal has been sitting open longer than that, the code is gone and the page tells you so. Run codecharter login again and use the new code.

"Your account has no active subscription"

Approving a device only mints a license if the approving account has an active subscription. Two places tell you when it does not, and neither of them costs you the code:

  • In the browser. The approval page refuses the approval and explains why, with a link to your billing page. Nothing is recorded, so the code stays valid and the machine keeps waiting. Subscribe in another tab, come back, and approve the same code — the sign-in then finishes normally.
  • On the waiting machine. If the subscription lapsed after you approved, the CLI prints Your account has no active subscription. Visit the portal to start a trial or subscribe. and exits with code 1 straight away, instead of waiting for the code to expire. Because the command has already stopped, run codecharter login again after subscribing and approve the new code it shows.

Neither case spends your approval, so nothing is left half-done in the portal.

Many sign-in attempts in a row

The sign-in endpoints are rate-limited per IP address. If you script the command in a loop, the portal answers 429 Too Many Requests with a Retry-After header telling you how many seconds to wait.

The machine is a CI runner

Do not sign a runner in with codecharter login. Give it an API key as a secret instead, see API keys in secrets. If a runner happens to be a machine somebody once signed in on, the API key in the environment takes precedence anyway, so the job never borrows a developer's identity.