Stephan-v
Stephan-v

Reputation: 20329

GitHub Clone with OAuth Access Token

Inside a script I am trying to clone a GitHub repository with an OAuth token.

According to this tutorial:

https://github.com/blog/1270-easier-builds-and-deployments-using-git-over-https-and-oauth

I should be able to build a command for it like this:

git clone https://<token>@github.com/owner/repo.git

If I try this manually with a proper access token, it still asks for my password.

If I try it on the commandline I am simply getting a repository not found error.

The article is from 2012 and I cannot find any API documentation for this. So I am wondering if this still works.

Upvotes: 285

Views: 708198

Answers (15)

Nimesh Vadgama
Nimesh Vadgama

Reputation: 1

The command-line to clone repo is as in below format

git clone https://oauth2:<your-token>@<github-clone-path-without-https-and-slash>

For example, you want to clone github : https://github.com/nimeshgit/myrepo.git and you have a token : AABBCD-XXYY-ZZ

then you can clone repo with below command line:

git clone https://oauth2:[email protected]/nimeshgit/myrepo.git

Upvotes: -1

Biddut
Biddut

Reputation: 457

Go to this link: https://github.com/settings/tokens

then copy the token and prepare following command and run it into bash

git clone https://<username>:<token>/<username>/<reponame>.git

Upvotes: 0

VonC
VonC

Reputation: 1328122

That should be better supported with Git 2.41 (Q2 2023), the credential subsystem learns to help OAuth framework.

See commit a5c7656 (21 Apr 2023) by M Hickford (hickford).
(Merged by Junio C Hamano -- gitster -- in commit 2ca91d1, 10 May 2023)

credential: new attribute oauth_refresh_token

Signed-off-by: M Hickford

Git authentication with OAuth access token is supported by every popular Git host including GitHub, GitLab and BitBucket.
Credential helpers Git Credential Manager (GCM) and git-credential-oauth generate OAuth credentials.
Following RFC 6749, the application prints a link for the user to authorize access in browser.
A loopback redirect communicates the response including access token to the application.

For security, RFC 6749 recommends that OAuth response also includes expiry date and refresh token.
After expiry, applications can use the refresh token to generate a new access token without user reauthorization in browser.
GitLab and BitBucket set the expiry at two hours.
(GitHub doesn't populate expiry or refresh token.)

However the Git credential protocol has no attribute to store the OAuth refresh token (unrecognised attributes are silently discarded).
This means that the user has to regularly reauthorize the helper in browser.
On a browserless system, this is particularly intrusive, requiring a second device.

Introduce a new attribute oauth_refresh_token.
This is especially useful when a storage helper and a read-only OAuth helper are configured together.
Recall that credential fill calls each helper until it has a non-expired password.

    helper = storage  # eg. cache or osxkeychain
    helper = oauth

The OAuth helper can use the stored refresh token forwarded by credential fill to generate a fresh access token without opening the browser.
See https://github.com/hickford/git-credential-oauth/pull/3/files for an implementation tested with this patch.

Add support for the new attribute to credential-cache.
Eventually, I hope to see support in other popular storage helpers.

Alternatives considered: ask helpers to store all unrecognised attributes.
This seems excessively complex for no obvious gain.
Helpers would also need extra information to distinguish between confidential and non-confidential attributes.

Workarounds: GCM abuses the helper get/store/erase contract to store the refresh token during credential get as the password for a fictitious host (I wrote this hack).
This workaround is only feasible for a monolithic helper with its own storage.

git credential now includes in its man page:

oauth_refresh_token

An OAuth refresh token may accompany a password that is an OAuth access token. Helpers must treat this attribute as confidential like the password attribute. Git itself has no special behaviour for this attribute.


With Git 2.43 (Q4 2023), the way authentication related data other than passwords (e.g. oath token and password expiration data) are stored in libsecret keyrings has been rethought.

See commit 0ce02e2 (16 Jun 2023) by M Hickford (hickford).
(Merged by Junio C Hamano -- gitster -- in commit e839608, 28 Aug 2023)

credential/libsecret: store new attributes

Signed-off-by: M Hickford

d208bfd (credential: new attribute password_expiry_utc, 2023-02-18, Git v2.40.0-rc1 -- merge) and a5c7656 (credential: new attribute oauth_refresh_token, 2023-04-21, Git v2.41.0-rc0 -- merge listed in batch #18) introduced new credential attributes.

libsecret assumes attribute values are non-confidential and unchanging, so we encode the new attributes in the secret, separated by newline:

hunter2
password_expiry_utc=1684189401
oauth_refresh_token=xyzzy

This is extensible and backwards compatible.
The credential protocol already assumes that attribute values do not contain newlines.

Alternatives considered: store password_expiry_utc in a libsecret attribute.
This has the problem that libsecret creates new items rather than overwrites when attribute values change.


With Git 2.43 (Q4 2023), the way authentication related data other than passwords (e.g. oath token and password expiration data) are stored in libsecret keyrings has been rethought.

See commit 0ce02e2 (16 Jun 2023) by M Hickford (hickford).
(Merged by Junio C Hamano -- gitster -- in commit e839608, 28 Aug 2023)

credential/libsecret: store new attributes

Signed-off-by: M Hickford

d208bfd (credential: new attribute password_expiry_utc, 2023-02-18, Git v2.40.0-rc1 -- merge) (credential: new attribute password_expiry_utc, 2023-02-18) and a5c7656 (credential: new attribute oauth_refresh_token, 2023-04-21, Git v2.41.0-rc0 -- merge listed in batch #18) (credential: new attribute oauth_refresh_token) introduced new credential attributes.

libsecret assumes attribute values are non-confidential and unchanging, so we encode the new attributes in the secret, separated by newline:

hunter2
password_expiry_utc=1684189401
oauth_refresh_token=xyzzy

This is extensible and backwards compatible.
The credential protocol already assumes that attribute values do not contain newlines.

Alternatives considered: store password_expiry_utc in a libsecret attribute.
This has the problem that libsecret creates new items rather than overwrites when attribute values change.


With Git 2.44 (Q1 2024), batch 15, the wincred credential backend has been taught to support OAuth refresh token the same way as credential-cache and credential-libsecret backends.

See commit f061959 (28 Jan 2024) by M Hickford (hickford).
(Merged by Junio C Hamano -- gitster -- in commit bec9160, 08 Feb 2024)

credential/wincred: store oauth_refresh_token

Signed-off-by: M Hickford

a5c7656 ("credential: new attribute oauth_refresh_token) introduced a new confidential credential attribute and added support to credential-cache.
Later 0ce02e2f (credential/libsecret: store new attributes", 2023-06-16, Git v2.41.0-rc0 -- merge listed in batch #18) added support in credential-libsecret.

To add support in credential-wincred, we encode the new attribute in the CredentialBlob, separated by newline:

hunter2
oauth_refresh_token=xyzzy

This is extensible and backwards compatible.
The credential protocol already assumes that attribute values do not contain newlines.

This fixes test "helper (wincred) gets oauth_refresh_token" when t0303-credential-external.sh is run with GIT_TEST_CREDENTIAL_HELPER=wincred.
This test was added in a5c7656 (credential: new attribute oauth_refresh_token, 2023-04-21).

Alternatives considered: store oauth_refresh_token in a wincred attribute.
This would be insecure because wincred assumes attribute values to be non-confidential.


With Git 2.45 (Q2 2024), batch 2, credential helper based on libsecret (in contrib/) has been updated to handle an empty password correctly.

See commit 8f1f202 (19 Feb 2024) by M Hickford (hickford).
(Merged by Junio C Hamano -- gitster -- in commit 70dadd5, 27 Feb 2024)

libsecret: retrieve empty password

Signed-off-by: M Hickford

Since 0ce02e2 ("credential/libsecret: store new attributes", 2023-06-16, Git v2.43.0-rc0 -- merge) a test that stores empty username and password fails when t0303-credential-external.sh is run with GIT_TEST_CREDENTIAL_HELPER=libsecret.

Retrieve empty password carefully.
This fixes test:

ok 14 - helper (libsecret) can store empty username

Upvotes: 1

Andris
Andris

Reputation: 5420

Just use the HTTPS address to clone with the key as the user, so:

git clone https://oauth2:[email protected]/username/repo.git

or

git clone https://username:[email protected]/username/repo.git

Upvotes: 376

Mehmet Kaplan
Mehmet Kaplan

Reputation: 2372

For lazy folks like future me:

  1. Generate your "Personal access tokens (classic)" from https://github.com/settings/tokens and copy it. (This will behave like password in next steps.)

  2. Run the following git command. It signals git to store the credentials (which will come in step 3)

    git config --global credential.helper manager-core
    git config --global credential.helper store
    
  3. In your first clone you will be asked username and password provide your password coming from item 1 above:

    git clone https://[email protected]/GithubUserName/repo-to-clone.git
    

For next git commands you should not be asked for credentials.

Upvotes: 10

Colonel Panic
Colonel Panic

Reputation: 137722

You need to include a username before the token. GitHub accepts any username. oauth2 works for both GitHub and GitLab.

git clone https://oauth2:[email protected]/owner/repo.git

However including credentials in https Git URL is considered bad practice because it risks inadvert credential exposure from config files and command history.

Also, it will break when the token expires. This is as short as two hours for hosts such as GitLab and BitBucket.

More secure and more reliable is to use a credential-generating helper such as Git Credential Manager (included in Git for Windows) or git-credential-oauth (included in several Linux distributions).

The first time you authenticate, the helper opens a browser window to the host. Subsequent authentication is non interactive.

These helpers refresh expired OAuth tokens as necessary.

Upvotes: 2

Robert Moskal
Robert Moskal

Reputation: 22553

As of Spring 2023, if you have your access token scopes set correctly, this is a one liner for cloning a repo (no need for any further interaction):

git clone https://ghp_foo_etc:[email protected]/bar/baz-phoenix.git

Where ghp_foo_etc is your access token. That's it! This is similar to how npm accesses code in private repos. Theres' no need to provide a user name.

I'm pretty certain its' always been so!

Upvotes: 4

Rad
Rad

Reputation: 5012

Just for those who still have problem "cloning a private repository with a readonly FG token: "remote: Write access to repository not granted."

The error message is a bit misleading. In my case the issue was with the configuration:

  1. Create a readonly token (content: readonly)
  2. Make sure the resource owner is properly set.
  3. For organizations, you have to complete "personal-access-tokens-onboarding".
  4. Clone the repository using https://oauth2:[email protected]/myuser/myrepo.git (note the username, as suggested by others, it's oauth2)

With all of the above, I managed to clone a private repository with a readonly token (and no, there was no write access 🙂)

Upvotes: 3

Ayudh
Ayudh

Reputation: 1763

For me none of the answers above worked. It turns out I had set an expiration of one month on my token so I had to recreate the token using the instructions here: https://www.shanebart.com/clone-repo-using-token/

Upvotes: 2

dgggggggğ
dgggggggğ

Reputation: 669

go to https://github.com/settings/tokens and generate a new token, remember to enable access to the repo, after that, you can do the following to clone the repo.

git clone https://<token>@github.com/owner/repo.git

Note: owner is your username if it's your repository else keep username of repository owner(one with all the rights of repo).

Upvotes: 27

hobbydev
hobbydev

Reputation: 1729

Please try this.

git clone `https://oauth2:[email protected]/username/repo.git`

For example, git clone https://oauth2:[email protected]/gituser/testrepo.git

Upvotes: 48

Amit Levy
Amit Levy

Reputation: 1193

Just clone the repository with HTTP like so:

git clone https://github.com/myuser/myrepo.git

When prompted for Username, fill your username.

When prompted for Password, fill the token instead.

Upvotes: 73

Insa
Insa

Reputation: 21

In .net core you can do in this way when dealing with Azure DevOps Repo:

 public void CloneRepository()
        {
            var _gitURL = "URLofGitRemoteRepository";
            var _userName = "PersonalAccessToken";
            var _pswd = ""; //Keep it blank

            var co = new CloneOptions();
            co.CredentialsProvider = (_url, _user, _cred) => new UsernamePasswordCredentials { Username = _userName, Password = _pswd };

            Repository.Clone(_gitURL, filePath, co);
        }

Upvotes: 2

t.ios
t.ios

Reputation: 1042

Do whatever works for you from these two choices

In your terminal

$ git clone your_repo_url Username:your_token Password:

... there is no password

In your git client app

i.e. Sourcetree, GitKraken, and the GitHub client.

Enter your repo_url (obvsiously without the '$ git clone part')

Username:your_token Password:

... there is no password

OR i.e. in Sourcetree, open preferences and then go to advanced, enter the hostname (i.e. www.x.com) and userName (i.e. your_token)

enter image description here

👍

Upvotes: 32

Stephan-v
Stephan-v

Reputation: 20329

I turned out to be a scope issue. I of course needed full repo scope since I was trying to clone a private repository.

It's a shame Github does not have some clearer error messages for these kind of things, but security wise I understand why.

For anyone trying to figure out what is wrong when trying out something like this, I would suggest to create a personal access token with full access to everything:

settings > developer settings > personal access tokens > generate new token

This way you can easily test if it is a scope issue by comparing your token with a personal access token that has access rights for everything.

Thanks for anyone who still took the time to read this.

Upvotes: 129

Related Questions