Secure Git Credentials Management on Linux with Git Credential Manager and libsecret: Auto-save GitHub/GitLab Tokens

Git tutorial - IT technology blog
Git tutorial - IT technology blog

The Real Problem: Tired of Typing Your Password/Token Every Time?

After GitHub dropped password authentication in August 2021, I had to switch to Personal Access Tokens (PAT). And honestly, pasting a 40-character token every time I ran git push got old fast. On top of that, tokens expire every 30–90 days, so you have to generate a new one and update it all over again.

Over six months of real-world deployments, I tried four different approaches — from the simplest to what I’m actually using today. This article summarizes everything I learned along the way.

Comparing 4 Ways to Store Git Credentials on Linux

Option 1: git-credential-store (plaintext file)

Built into Git, no extra setup required. One command and you’re done:

git config --global credential.helper store

Credentials are saved to ~/.git-credentials in plaintext:

https://username:[email protected]

Pros: Zero setup, works immediately, no additional packages needed.

Cons: Token is stored in plaintext — any process running as your user can read it. If your machine is compromised, your token is fully exposed. Not suitable for shared machines or production servers.

Option 2: git-credential-cache (in-memory storage)

# Store credentials in RAM, expires after 1 hour (3600 seconds)
git config --global credential.helper 'cache --timeout=3600'

Pros: Credentials never touch disk, safer than store.

Cons: Lost on reboot, requires re-entry. Doesn’t work on systems without Unix sockets (some minimal distro setups). On a 24/7 server, re-entering credentials every hour is not practical.

Option 3: libsecret (integrated with GNOME Keyring / KWallet)

On Ubuntu or Fedora with GNOME, this is a great option that many people overlook. libsecret talks directly to the Secret Service API — credentials are encrypted by the OS, not the app, and stored in the system keyring.

# Install libsecret
sudo apt install libsecret-1-0 libsecret-1-dev git

# Build git-credential-libsecret
cd /usr/share/doc/git/contrib/credential/libsecret
sudo make

# Configure
git config --global credential.helper /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret

Pros: Credentials encrypted by the OS, native integration with GNOME/KDE, no separate daemon needed.

Cons: Only works with a desktop environment (GNOME, KDE). On headless servers, GNOME Keyring won’t start — it requires a D-Bus session and GUI environment to function.

Option 4: Git Credential Manager (GCM) — Cross-platform

Microsoft built this and open-sourced it. GCM handles full OAuth2 flows — no need to manually create a PAT, just log in once through the browser and you’re set. It supports GitHub, GitLab, Bitbucket, and Azure DevOps out of the box. On Linux, GCM is flexible with multiple storage backends.

Pros: Automatic OAuth2 (no manual PAT needed), works on both desktop and headless servers, multiple storage backends, cross-platform.

Cons: Requires .NET runtime, binary is fairly large (~100MB). If you only use one service, it may be overkill.

Analysis: Which Option Should You Choose?

Criteria store cache libsecret GCM
Security ❌ Plaintext ✅ RAM only ✅ Encrypted ✅ Encrypted
Persistent
Headless server ✅ (with secret-service or plaintext)
Desktop Linux
Automatic OAuth2
Setup complexity Very easy Very easy Moderate Moderate

My practical takeaways:

  • Desktop Linux (Ubuntu, Fedora, Mint): Use libsecret — native, lightweight, secure, integrates with your existing keyring.
  • Headless server / VPS: Use GCM with a GPG-encrypted plaintext store, or even simpler — just use SSH keys (no credential helper needed at all).
  • Teams using multiple services (GitHub + GitLab + Bitbucket): Use GCM for automatic OAuth2.

Setup: libsecret on Ubuntu/Debian Desktop

Step 1: Install dependencies

sudo apt update
sudo apt install libsecret-1-0 libsecret-1-dev git make gcc

Step 2: Build git-credential-libsecret

# Locate the source path (varies by git version)
ls /usr/share/doc/git/contrib/credential/libsecret/

# Build
cd /usr/share/doc/git/contrib/credential/libsecret/
sudo make

# Verify
ls -la git-credential-libsecret

Step 3: Set global configuration

git config --global credential.helper /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret

# Verify configuration
cat ~/.gitconfig | grep credential

The first time you run git push, you’ll be prompted for your token. Enter it once and libsecret saves it to GNOME Keyring. Every subsequent operation retrieves it automatically — no re-entry needed.

Setup: Git Credential Manager on a Headless Server

Step 1: Download and install GCM

# Check for the latest release at: https://github.com/git-ecosystem/git-credential-manager/releases
GCM_VERSION="2.5.1"
wget https://github.com/git-ecosystem/git-credential-manager/releases/download/v${GCM_VERSION}/gcm-linux_amd64.${GCM_VERSION}.deb

sudo dpkg -i gcm-linux_amd64.${GCM_VERSION}.deb

Step 2: Configure a storage backend

On a headless server, GCM can’t use GNOME Keyring. You have two options:

# Option A: GPG-encrypted file (recommended)
git-credential-manager configure
git config --global credential.credentialStore gpg

# Generate a GPG key if you don't have one
gpg --gen-key

# Option B: Plaintext (equivalent to git-credential-store but routed through GCM)
git config --global credential.credentialStore plaintext

Step 3: Test with GitHub

# Clone a private repo to test
git clone https://github.com/your-org/private-repo.git

# GCM will open a browser (if available) or display a URL to authenticate
# After the first authentication, all subsequent git operations are automatic

A Real Incident I Ran Into

I once lost important code from an accidental force push to the wrong branch — ever since, I’m extra careful with git push --force. But that same incident made me realize I had been casually pasting tokens directly into the terminal, completely overlooking the fact that shell history can persist those tokens.

# DON'T do this — token exposed in history!
git clone https://username:[email protected]/org/repo.git

# Check bash history
history | grep ghp_
# → This is exactly why you need a credential helper instead of inline tokens

After switching to libsecret, my tokens no longer appear in the command line or shell history. Git retrieves the token from the keyring internally — much cleaner.

Bonus: Managing Multiple GitHub Accounts Simultaneously

Got both a personal and a work GitHub account? GCM handles this better than libsecret:

# Per-repo configuration (overrides global)
cd ~/work-project
git config credential.https://github.com.username work-username

# Or use SSH with multiple keys (my preferred approach)
# Add to ~/.ssh/config
Host github-personal
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_personal

Host github-work
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519_work

# Clone using the alias
git clone git@github-personal:username/personal-repo.git
git clone git@github-work:org/work-repo.git

Cleaning Up Old Credentials

Need to remove old credentials or reset and start fresh? Here are the relevant commands for each method:

# Remove stored credentials (libsecret)
git credential-libsecret erase
protocol=https
host=github.com
# Press Ctrl+D

# Clear the entire cache (git-credential-cache)
git credential-cache exit

# Manually delete the store file
rm ~/.git-credentials

Wrapping Up

If you’re on a Linux desktop, start with libsecret — it’s lightweight, native, and takes about 10 minutes to set up. If you’re managing servers or juggling multiple Git services, GCM is worth the initial setup time. And if your server only needs to pull/push from a single repo, just deploy an SSH key and forget about credential helpers altogether — that’s what I use on most of my production VPS instances.

Share: