Enable OS-keychain storage¶
Out of the box, credentials ships a no-op stub backend: Store
/ Retrieve /
Delete return
ErrCredentialUnsupported, ModeKeychain is never offered, and no keychain code is
linked. This guide turns on real OS-keychain support — and shows how to turn it back
off for a regulated build.
Activate it: one blank import¶
Add a single blank import to your tool's main package:
// cmd/mytool/main.go
import (
_ "gitlab.com/phpboyscout/go/credentials/keychain" // registers the backend at init()
)
The subpackage's init() calls RegisterBackend
with a go-keyring-backed implementation. From
that point on:
KeychainAvailablereportstrue,AvailableModesincludesModeKeychain,- and
Probeperforms a live canary round-trip.
The backend maps to the platform store automatically: macOS Keychain, Linux Secret Service (GNOME Keyring / KWallet) over D-Bus, Windows Credential Manager.
Gate the UI on Probe, not just availability¶
KeychainAvailable tells you a backend is registered; it does not tell you the
keychain works right now. A headless Linux host with no Secret Service provider, or
a locked macOS keychain, will reject writes at use time. Always gate the offer on a
live Probe:
ctx, cancel := context.WithTimeout(ctx, credentials.KeychainOpTimeout)
defer cancel()
if credentials.Probe(ctx) {
// safe to offer ModeKeychain — the canary Set→Get→Delete succeeded
}
ModeChoices already does this for you when you pass Probe(ctx) as its
keychainUsable argument — see Choose a storage mode.
Store and resolve¶
With the backend active, the secret round-trips through the platform store and the
config records only a service/account reference:
// store (setup time)
err := credentials.Store(ctx, "mytool", "github.auth", token)
// resolve (runtime)
token, err := credentials.Retrieve(ctx, "mytool", "github.auth")
switch {
case err == nil:
// use token
case errors.Is(err, credentials.ErrCredentialNotFound):
// reachable keychain, no entry — fall through to your next source
case errors.Is(err, credentials.ErrCredentialUnsupported):
// no backend registered — fall through
}
Deactivate it: the regulated-build opt-out¶
To ship a build that touches no keychain IPC, omit the blank import. Keep it in a dedicated file so a build variant can drop it cleanly:
// cmd/mytool/keychain.go — delete this file for a keychain-free build
package main
import _ "gitlab.com/phpboyscout/go/credentials/keychain"
With the import gone, Go's linker dead-code elimination keeps go-keyring, godbus, and
wincred out of the binary. Nothing reaches a D-Bus session bus, and an SBOM taken
against the linked artefact shows a clean surface. The tool still runs — it just
falls back to the stub backend, so ModeKeychain is never offered and resolvers fall
through env/literal as normal.
For why this is a subpackage rather than a separate module — and how to verify the opt-out — see The keychain opt-out.
Related¶
- Choose a storage mode
- Test the keychain on a headless host — verify the round-trip on a server, container, or CI runner
- Implement a custom backend — for Vault / SSM / 1Password
- The keychain opt-out