Where to store my Git personal access token?

GitAccess Token

Git Problem Overview


Is it necessary to store the personal access token somewhere locally on the machine after generating it in GitHub?

If yes, is there any preferred way where it could be stored?

Git Solutions


Solution 1 - Git

> Half the point of passwords is that (ideally) you memorize them and the system hashes them, so therefore they're never stored anywhere in plain text.
Yet GitHub's personal access token system seems to basically force you to store the token in plain text?

First, a PAT (Personal Access Token) is not a simple password, but an equivalent that:

  • you can generate multiple time (for instance, one per machine from which you need to access GitHub repository)
  • you can revoke at any time (from the GitHub web interface), which makes that PAT obsolete, even if it lingers around on one of those machines.

That differs from your password, which is unique to your account, and cannot be easily changed without having to also modify it everywhere you happen to use it.


Since a PAT can be used in place of a password when performing Git operations over HTTPS with Git on the command line or the API, you can use a git credential helper to cache it securely.
On Windows, for instance, that would use the Windows Credential Manager, through the GCM -- Git Credential Manager -- for Windows, Mac or Linux:

git config --global credential.helper manager-core

The first time you are pushing to a repo, a popup will ask for your credentials: username and your PAT.
The next time, it won't ask, and reuse directly that PAT, which remains stored securely in your Credential Manager.

A similar idea applies for Mac with the OSX keychain, and Linux with the GNOME Keyring (in 2021, it would need a DBus session and libsecret), but in 2021, GCM-Core covers those use cases.
The idea remains: store the PAT in an encrypted credentials store.


As mentioned above, the more modern solution (Q4 2020) is Microsoft Git-Credential-Manager-Core

git config --global credential.helper manager-core

You need for that to install git-credential-manager-core, downloading its latest release, like gcmcore-linux_amd64.2.0.474.41365.deb

sudo dpkg -i <path-to-package>
git-credential-manager-core configure

Although, with GCM (Git-Credential-Manager-Core) on Linux, as noted by Mekky Mayata in the comments, you need to define a git config --global credential.credentialStore first.

See "Credential stores on Linux":

> There are four options for storing credentials that Git Credential Manager (GCM) manages on Linux platforms: > >- freedesktop.org Secret Service API >- GPG/pass compatible files >- Git's built-in credential cache >- Plaintext files > > By default, GCM comes not configured.
You can select which credential store to use by setting the GCM_CREDENTIAL_STORE environment variable, or the credential.credentialStore Git configuration setting.

As noted by agent18 in the comments, using git-credential-libsecret after installing libsecret-1-0 and libsecret-1-dev is a good first step.
But, again, that should be now wrapped by credential-manager-core.

Solution 2 - Git

In my case, in Ubuntu, the accepted solution didn't work with a message like

> git: 'credential-manager' is not a git command

but store instead of manager worked well:

git config --global credential.helper store

Solution 3 - Git

Alternatively, you can create a ~/.netrc file in home directory and save your login credentials to it.

cat ~/.netrc
machine github.com login <login-id> password <token-password>

Solution 4 - Git

Tested on Ubuntu 20.04, almost fresh install, with Git 2.25.1 and unity 7.5.

Authentication basics

Github needs an authentication key (with certain rights tied to said authentication key). A particular auth key has certain rights, (read private repos, read write public repos etc...) and "acts as a password" coupled with rights which can be revoked whenever the user wants.

Personal Access Token

  1. We start with making a PAT. I.E., Settings --> Developer Settings--> Persaonl access tokens --> Generate new token --> Note --> set permissions (repo,repo_hook maybe) --> generate token
  2. git push the repo and type the generated token(very long password) as password when asked.

Storing the password in different ways

    • Can be done in a file and then using xclip to bring it back to clipboard and paste it everytime (Screw this)
    • Cache with the help of git commands git config credential.helper cache <time-limit-of-cache>. But you still have to somehow clipboard the password after the timelimit.
    • Store it permanently in a file with git commands git config credential.helper store (don't use --global). This is NOT ENCRYPTED. You can open the file and read it. (e.g., If someone gets access to your laptop they can pretty much read the Password using a bootable USB (assuming your whole system is not encrypted)).
    • Or go the encryption route as per here. It is not complicated at all. 3 simple steps.
sudo apt-get install libsecret-1-0 libsecret-1-dev
sudo make --directory=/usr/share/doc/git/contrib/credential/libsecret
    
git config credential.helper /usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret

This allows to store the password/personal access token in an encrypted format. The git config file can be found in the .git/config file in your loca repo as shown here, if you ever need it.

P.S. There are many places that suggest the use of Gnome-keyring but that is apparently deprecated.

Storing passwords/PATs for more than one account

This becomes tricky and it appears as @VonC suggests that we need a Git-Credential-Manager core (GCM core). This answer is enhanced based on my findings in this answer.

  1. First install GCM core

    1. Download latest .deb package
    2. sudo dpkg -i <path-to-package>
    3. git-credential-manager-core configure
    4. git config --global credential.credentialStore secretservice as we use libsecret
  2. Get latest git

    In my case I had git 2.25 and got error error: unknown option 'show-scope'. It appears that GCM core is using higher git (atleast 2.26).

    So install the latest and greatest git as per here:

     sudo add-apt-repository ppa:git-core/ppa
     sudo apt-get update
     apt list git # shows the latest git currently 2.31
     sudo apt-get install git #or sudo apt-get upgrade
    
  3. Update git remote path with username built in

    GCM core needs this to identify the different accounts.:(

     git remote set-url origin https://[email protected]/user1/myRepo1.git
     git remote set-url origin https://[email protected]/user1/myRepo1.git
                                   ^^^^^
    

Your ~/.gitconfig file will thus have the following :

[credential]
   helper = /usr/bin/git-credential-manager-core
   credentialStore = secretservice
[credential "https://dev.azure.com"]
   useHttpPath = true

Solution 5 - Git

To store your credentials in cache and avoid logging in every time you perform a git action, follow these steps:

  1. Navigate to your local repository folder.

  2. In the current folder's terminal: git config --global --replace-all credential.helper cache

  3. Perform git push or git pull.

  4. Login with username and access token (access token is your password). The token can be setup in GitHub and have access to repo, workflow, write:packages and delete:packages.

  5. Repeat git push or any git action and you'll find that it doesn't ask for login credentials from now on.

Solution 6 - Git

I like to keep them encrypted within the repository and load them using .envrc (https://direnv.net/)

For doing this I use ssh-vault to encrypt the data using my ssh keys that GitHub already is exposing, for example:

echo MY_TOKEN="secret" | ssh-vault -u <github-user> create > my-encypted-vars.ssh

Then the content of .envrc looks something like this:

echo "Enter ssh key password"
context=$(ssh-vault view $HOME/projects/my-encrypted.ssh | tail -n +2)
export ${context}

This will decrypt the data in my-encrypted-vars.ssh file and set MY_TOKEN into my environment variables every time I cd into the project dir.

By doing this tokens/variables are stored "safely" and always ready to use as environment variables

Solution 7 - Git

try enabling this to help with persisting across push / pulls

git config credential.helper store

For ongoing cloning of repo / for macOS users / install iTerm2 https://iterm2.com/

enter image description here

Enable Toolbelt

enter image description here

Just click the snippet whenever you need it. P.S. you are using oh-my-zsh, aren't you? https://github.com/ohmyzsh/ohmyzsh

Solution 8 - Git

You can cache your credentials for a defined time using:

git config --global credential.helper cache

The default cache period is 900 sec (15 min) but can be changed with:

git config --global credential.helper 'cache --timeout=3600'

See the following Github page:

> https://docs.github.com/en/github/using-git/caching-your-github-credentials-in-git

This is not a permanent store and as per other comments credentials should not be stored in plain text, which is a security risk. I use a password manager (https://bitwarden.com/) to store the PAT (Personal Access Token) then copy it in for the first use, where it is then cached. A PAT is required if you enable 2FA on your Github account.

Solution 9 - Git

Well, you have to save the token somewhere, when you don't want to type it each time your app asks for it :-)

A good solution is using environment variables, as already suggested in one comment.

But you still have to set the environment variable somewhere.
On Windows (which I'm using), you could use the dialog box in the system settings (I don't know if other operating systems have something similar).

I don't do this, I prefer a script in my project.
In a private project, you may commit this to source control, but this is a matter of preference.

In one of my personal projects, I'm calling the GitHub API as well, using a personal access token.
It's a command line app and the end user will save the token in a config file (which is OK).

But I need the token for development as well, because the project has integration tests where I'm calling the GitHub API.

And that project is public on GitHub, so I couldn't save the token in source control.

What I did is this:

  • I have a batch file (remember, I'm on Windows) called environment-variables.bat which sets all required environment variables including the access token
  • I'm calling this in my build script and in the batch file I'm using to run my tests
  • environment-variables.bat is ignored in source control
  • But in source control, there's environment-variables.bat.sample instead, which contains the same, but a fake token/password.

So I can just rename this file to environment-variables.bat, replace the fake password by the real one, and everything works.


This is not the perfect solution for all cases, though.

In my project, I have the problem that I need to use more tokens/passwords for more APIs in the future.

So the number of tokens in my environment-variables.bat will increase, making it difficult for potential contributors to actually execute all integration tests. And I still don't know how to deal with that.

Solution 10 - Git

In my use case, I store the PAT in a password manager, e.g. LastPass, KeePass, 1Password. When I need it in a Linux environment ( e.g. Docker ), I save the PAT in an environment variable and then use git's credential helper setting. For example:

git config --global credential.helper 'cache --timeout 600'

<< eof tr -d ' ' | git credential-cache store 
  protocol=https
  host=github.com
  username=nonce
  password=${GITHUB_PAT}
eof

With a PAT the username can be anything except blank. Here's a gist that elaborates:

https://gist.github.com/rwcitek/da862e9e27cc28d3e96e62a2ca4b2b64

Solution 11 - Git

Basically I did this on my machine:

> https://gist.github.com/bsara/5c4d90db3016814a3d2fe38d314f9c23

My profile script is slightly different than described:

env=~/.ssh/agent.env

agent_load_env () { test -f "$env" && . "$env" >| /dev/null ; }

agent_start () {
    (umask 077; ssh-agent >| "$env")
        . "$env" >| /dev/null ; 
}

agent_load_env

# agent_run_state: 0=agent running w/ key; 1=agent w/o key; 2= agent not running
agent_run_state=$(ssh-add -l >| /dev/null 2>&1; echo $?)

if [ ! "$SSH_AUTH_SOCK" ] || [ $agent_run_state = 2 ]; then
    agent_start
    ssh-add
elif [ "$SSH_AUTH_SOCK" ] && [ $agent_run_state = 1 ]; then
    ssh-add
fi

unset env

Solution 12 - Git

You can store the github https token using pass.

Two alternatives to map a git host to a pass entry:

  • bash script to map to the right pass entry:
#!/usr/bin/env bash
# assuming "get" action from git and a config like this
# git config --global credential.helper $XDG_BIN_HOME'/git_credentials_from_pass $@'
while IFS= read -r line
do
  echo "$line"
  if [[ "$line" =~ host=.*github.com.* ]]; then
      echo "username=your_user_name"
      echo "password=$(pass show token_github.com/your_username)"
  #else ...
  fi
done

Change your_username and token_github.com the way you set it up with pass insert.

This adds the token to pass without typing or pasting twice:

echo your_github_token | sed p | pass add token_github.com/your_username
git config --global credential.helper '!pass-git-helper $@'

pass-git-helper needs an ini-file to map between the git request and the pass entry. ${XDG_CONFIG_HOME}/pass-git-helper/git-pass-mapping.ini example:

[DEFAULT]
username_extractor=entry_name
[github.com*]
target=token_${host}/your_github_username

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKrzysztof SłowińskiView Question on Stackoverflow
Solution 1 - GitVonCView Answer on Stackoverflow
Solution 2 - GitJavier MontónView Answer on Stackoverflow
Solution 3 - GitzrashView Answer on Stackoverflow
Solution 4 - Gitagent18View Answer on Stackoverflow
Solution 5 - GitAswathView Answer on Stackoverflow
Solution 6 - GitnbariView Answer on Stackoverflow
Solution 7 - GitjohndpopeView Answer on Stackoverflow
Solution 8 - GitEd_NView Answer on Stackoverflow
Solution 9 - GitChristian SpechtView Answer on Stackoverflow
Solution 10 - GitRobert CitekView Answer on Stackoverflow
Solution 11 - GitmemoView Answer on Stackoverflow
Solution 12 - GitRoland PuntaierView Answer on Stackoverflow