When a developer runs snyk auth for the first time, the CLI kicks off a browser-based login, waits for a callback, and drops a credential onto the local filesystem — usually without the developer ever seeing the raw value or thinking about where it landed. That credential then authenticates every snyk test, snyk monitor, and snyk container test call the CLI makes for as long as it lives, which for a classic Snyk personal API token is indefinitely, unless someone manually rotates it.
Snyk's CLI is open source, and its authentication behavior is documented on docs.snyk.io, so none of this is secret — but it's rarely read closely. This post walks through what actually happens during snyk auth, where the resulting token is stored, how the newer OAuth2 option changes the risk profile, and how the CLI decides which credential to use when several are present at once (a common source of CI misconfigurations).
How does snyk auth get a token onto your machine?
The command opens your default browser to a Snyk login URL and waits for the web session to hand a token back to the CLI process. If the CLI can't open a browser — a headless build agent, a remote shell, a locked-down container — it prints the login URL to the terminal instead and asks you to open it manually, then complete the sign-in in that browser tab. Once you authenticate against app.snyk.io (via email/password, SSO, or an OAuth identity provider depending on your org's settings), Snyk's web application returns your account's API token to the waiting CLI process, which writes it to local config and immediately becomes the active credential for that machine.
There's also a manual path: snyk auth <token>, where you paste in an API token copied directly from your account settings page at app.snyk.io/account. This is the mechanism most people actually use on CI runners and shared build servers, since there's no browser to complete a login flow in the first place.
Where does the CLI store the token after login succeeds?
The token lands in a plaintext JSON config file in your user profile, not in an OS-level credential store like macOS Keychain or Windows Credential Manager. Snyk's CLI is a Node.js application and uses the widely-adopted configstore library for local settings, which writes to a predictable path under your home directory — on Linux and macOS that's typically ~/.config/configstore/snyk.json, with a comparable path under your user profile's .config directory on Windows. Open that file and you'll find a small JSON object with an api key holding the raw token string, plus a handful of CLI preference fields.
This matters because it's the same class of storage pattern used by dozens of other developer CLIs (think early versions of tools that predate broad keychain integration): convenient, cross-platform, and readable by any process or backup job with access to your home directory. There's no encryption at rest and no OS-level access control beyond normal file permissions. If that file ends up in a dotfiles repo, a machine image snapshot, a support bundle, or a container layer that gets pushed to a registry, the token travels with it in fully usable form.
What does the token itself look like, and how long does it live?
A classic Snyk personal API token is a UUID-formatted string — the same 36-character hyphenated hex format you'd recognize from 12345678-90ab-cdef-1234-567890abcdef — and it doesn't expire on a schedule. It stays valid until a user manually regenerates it from the account settings page, or an org admin revokes it. That's a meaningful design choice: unlike a short-lived session cookie, this single string is a durable bearer credential tied to a specific user's Snyk account and, in most default configurations, carries that user's full API scope — reading and writing project data, triggering scans, and pulling org- and project-level results across whatever organizations that account belongs to.
Because the token isn't scoped down by default, a copy of snyk.json lifted from a compromised laptop or CI cache is functionally equivalent to that developer's own Snyk session from an API perspective, without needing their password or a second factor.
How does the CLI decide which credential to use in CI?
Precedence runs from most explicit to least explicit: a token passed directly on the command line or via the SNYK_TOKEN environment variable overrides whatever is sitting in the local configstore file, which is why most CI documentation from Snyk recommends injecting SNYK_TOKEN as a pipeline secret rather than running snyk auth interactively on a build agent. snyk config set api=<token> and snyk config get api let you set or inspect the persisted value directly without going through the browser flow at all, which is the pattern most infrastructure-as-code and Docker-based CI setups use — bake the token in as a masked secret variable, reference it via SNYK_TOKEN, and skip local persistence entirely.
The practical risk shows up when teams do both: an engineer authenticates locally via snyk auth for day-to-day scanning, and the same machine's environment also has SNYK_TOKEN set globally in a shell profile for convenience. Now there are two live, valid tokens for the same account sitting on one machine, and secret scanners looking only for environment variables will miss the one sitting in configstore.
What changed when Snyk added OAuth2-based authentication?
Snyk introduced an OAuth2 authentication path — invoked with an --auth-type=oauth2-style flag per current CLI documentation — primarily for enterprise customers who enforce SSO and want to disallow long-lived personal API tokens entirely. Instead of a single static bearer token, this flow issues a token set: a short-lived access token plus a refresh token, both persisted locally so the CLI can silently refresh the access token without prompting the user to log in again every session. Functionally this narrows the exposure window if the local config file leaks, because the access token portion expires on its own; the tradeoff is that the refresh token becomes the new long-lived secret worth protecting, so the underlying "credential sitting in a local JSON file" problem doesn't disappear — it just shifts which field in that file is the sensitive one.
Organizations on Snyk's Enterprise tier can also require SSO-based authentication and use service accounts with more narrowly scoped tokens for automation, which is Snyk's own recommended mitigation for the broad-scope problem inherent to personal API tokens in CI contexts.
Why does a leaked Snyk token matter more than it looks?
A stolen Snyk token doesn't just expose scan results — it can be used to enumerate your organization's project inventory, pull dependency and vulnerability data that maps your entire attack surface, and in some configurations trigger new scans or modify integration settings, all through a documented public API with no additional prompt for credentials. For an attacker doing reconnaissance ahead of a supply chain attack, a security tool's own API token is a uniquely efficient target: it's designed to aggregate exactly the kind of cross-repository, cross-org vulnerability visibility that's otherwise expensive to reconstruct manually. A single snyk.json file pulled from one developer laptop can expose that view across every project the account touches.
This is also why the file's ordinary location works against defenders — ~/.config/configstore/snyk.json isn't hidden, but it also isn't the first place most secret-scanning tooling looks, since scanners are generally tuned for .env files, cloud provider credential files, and hardcoded strings in source, not third-party CLI config directories.
How Safeguard Helps
Safeguard's software supply chain security platform is built around the assumption that credentials for developer tools — not just cloud and source-control secrets — are part of your attack surface, and that they routinely end up somewhere unintended: laptop backups, container image layers, CI cache artifacts, and shared build servers. Safeguard extends secret detection beyond the usual .env-and-cloud-key patterns to recognize CLI-local credential stores like Snyk's configstore files, so a stray API token doesn't have to match a hardcoded-string pattern in source code to get flagged.
Beyond detection, Safeguard maps which of your build pipelines and developer machines hold live security-tool credentials, helps enforce short-lived or scoped tokens over static personal ones wherever a vendor supports them, and surfaces stale or duplicate authentication (the "browser login plus global SNYK_TOKEN" pattern above) before it becomes an unmonitored second path into your tooling. For teams standardizing on tools like Snyk as part of their broader dependency and vulnerability management program, that visibility closes a gap that traditional secret scanners typically miss: the credentials your security tools themselves depend on.