credentials

package
v4.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package credentials stores and resolves the OAuth token of one profile: access token, refresh token, expiry and type.

Resolution order:

  1. GITLAB_MCP_REFRESH_TOKEN in the environment (CI, automation).
  2. The OS keyring — Secret Service on Linux, Keychain on macOS, Credential Manager on Windows — keyed by the profile name.
  3. A file under the profile directory, restricted to the current account (0600, or an ACL on Windows), written only when the keyring was unavailable, and warned about on every use.

A missing keyring entry falls through quietly. A broken keyring (no session bus, no secret service) also falls through, so a headless machine still works, and its error is reported if nothing else is found.

GitLab rotates the refresh token on every refresh and revokes the old one at once, so a refresh token from the environment works exactly once. The pair it rotates into is saved to the keyring or the file stamped with a hash of the variable's value, and while the variable still holds that value the stored descendant is used in its place. Without that, the second start after a refresh would present a spent token.

Index

Constants

View Source
const ServiceName = "gitlab-mcp"

ServiceName is the keyring service identifier.

Variables

View Source
var ErrKeyringSilent = errors.New("credentials: the profile records a token in the OS keyring and the " +
	"keyring returned nothing. It is more likely locked or unreachable than empty: unlock it and try again. " +
	"`gitlab-mcp login` writes a fresh token, which works around this rather than fixing it")

ErrKeyringSilent is what a keyring that answers "nothing" looks like when the profile says a token was stored in it.

The two are not the same and the advice differs. A missing token is fixed by logging in. A keyring that has the token and will not hand it over — locked, or a session bus that cannot reach the daemon — is fixed by unlocking it, and logging in again writes a second token beside the first without addressing the cause.

View Source
var ErrNotFound = errors.New("credentials: no token found; run `gitlab-mcp login`")

ErrNotFound means no token is stored anywhere.

Functions

This section is empty.

Types

type Backend

type Backend interface {
	Get(service, account string) (string, error)
	Set(service, account, secret string) error
	Delete(service, account string) error
}

Backend is the keyring contract. Tests substitute an in-memory one.

func OSKeyring

func OSKeyring() Backend

OSKeyring returns the production keyring backend.

type Source

type Source string

Source identifies where a token came from.

const (
	SourceEnv     Source = "env"
	SourceKeyring Source = "keyring"
	SourceFile    Source = "file"
)

Source values.

type Store

type Store struct {
	Profile  string
	Keyring  Backend
	FilePath string
	Env      func(string) string
	// Warn receives human-readable warnings; the plaintext fallback is
	// announced through it on every use rather than once at login.
	Warn func(string)
	// ExpectKeyring says the profile records that a token was saved to
	// the keyring. It changes only the error: with it, a keyring that
	// answers "nothing" is reported as a keyring that will not answer
	// rather than as a token that was never there.
	ExpectKeyring bool
	// contains filtered or unexported fields
}

Store resolves and saves the token for one profile.

func (*Store) Delete

func (s *Store) Delete() error

Delete removes the token from every store and reports every failure. Missing entries are fine. The environment is not a store.

func (*Store) EnvToken added in v4.1.3

func (s *Store) EnvToken() string

EnvToken is the refresh token the environment gives, read through config.Lookup as every setting is, so spaces alone are none.

func (*Store) Resolve

func (s *Store) Resolve() (*oauth2.Token, Source, error)

Resolve returns the token and where it came from.

The environment wins, except over a stored pair rotated from the very value it holds: that pair is the environment token's live successor. A token from the environment carries only the refresh token, so the first call refreshes it.

func (*Store) ResolveStored

func (s *Store) ResolveStored() (*oauth2.Token, Source, error)

ResolveStored returns the token from the keyring or the file, ignoring the environment override: it is the token logout can revoke and delete.

func (*Store) Save

func (s *Store) Save(tok *oauth2.Token) (Source, error)

Save stores the token in the keyring, or in the file when the keyring fails, and reports where it landed. A successful keyring save removes a stale plaintext copy, so there is one source of truth.

While the environment override is set, the saved pair is stamped as its successor (see Resolve); a pair saved without it is not.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL