1日ひとつだけ強くなる

おべんきょうのーと

Githubでhttpsを使っているのに403: Permission denied エラーが出た話

はじめに

gitを利用するすべての初心者に捧げます。

タイトルのとおりです。gitで利用している認証ヘルパーについての話があります。

目次

検証環境

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G1510
$ uname -a
Darwin hal0taso-2.local 15.6.0 Darwin Kernel Version 15.6.0: Tue Apr 11 16:00:51 PDT 2017; root:xnu-3248.60.11.5.3~1/RELEASE_X86_64 x86_64
$ git --version
git version 2.10.1 (Apple Git-78)

問題の概要

githubでpushすると以下のようなエラーが出ます。403 Forbiddenというやつです。

git push -u origin master
remote: Permission to hal00taso/test403error.git denied to hal0taso.
fatal: unable to access 'https://github.com/hal00taso/test403error.git/': The requested URL returned error: 403

おかしい….httpsを使っているはずなのに…と思って調べてみました

原因

原因は、リポジトリhal00taso/test403errorにpushする権限を持たないユーザーhal0taso(今回のケースでは0が一つ多いことに注意してください)でpushしようとしているためです。

リモートリポジトリにhttp(s)で接続していて認証が必要な場合には、基本的には毎回ログインを求められます。また、二段階認証が必要なシステムの場合、そのトークンはランダムかつunpronounceableなため、更に大変になります。この煩わしさを回避するためにGit にはcredential helperという認証情報を一時的、半永久的に記憶する仕組みがあり、ユーザーがいちいち認証情報を入力する手間を省いてくれます。特にmacではcredential helperにosxkeychainを設定することで、Macのキーチェーンアクセスで管理された認証情報を使用します。

そこで、現在有効になっている設定を確認してみましょう。

$ git config --list
credential.helper=osxkeychain
user.name=hal0taso
user.email=[YOUR EMAIL]
core.excludesfile=/Users/hal0taso/.gitignore_global

1行目を確認すると、確かにcredengial helperが有効になっていることが確認できます。

これはデフォルトの場合パスを無視してしまうため、前回github.comにログインしたユーザー名で認証しようとして失敗することが原因です。

対策

この対策としては以下の4つが挙げられます。

  1. https://hal00taso@github.com/としてURLにユーザー名を含める
  2. 全く記憶しないようにする: configからcredential.helperを消す
  3. 記憶している情報を消す: git credential reject コマンドを使う
  4. 記憶する際にパスも考慮するようにする: credential.useHttpPathtrueにする
  5. Macの場合、osx-keychainの認証情報を更新する

[2017/7/4追記] hubコマンドを使えという嬉しいマサカリが id:jtwp470 から飛んできたので、こちらに追記させていただきます。hubコマンドも対策必要です。 github.com

なお、gitの設定とそれが記述されているファイルパスは以下のようにして調べることができます。

$ git config --list --show-origin
file:/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig    credential.helper=osxkeychain
file:/Users/hal0taso/.gitconfig user.name=hal0taso
file:/Users/hal0taso/.gitconfig user.email=[YOUR EMAIL]
file:/Users/hal0taso/.gitconfig core.excludesfile=/Users/hal0taso/.gitignore_global

これを確認してみると、Macの場合はXcodeによって設定されているようです。

macでのOSX Keychainシステムの認証情報の更新、削除に関しては以下のリンクを参照してください。OSX Keychainシステムとは、Keychain Access.appから認証情報を取得する仕組みのことです。

Updating credentials from the OSX Keychain - User Documentation

[おまけ] git credential helperの裏側

さて、ではcredential helperはどのようにして動作しているのでしょうか。Gitのcredential helperのための基本的なコマンドはgit credentialです。これは、コマンドに引数を渡して、更に標準入力から必要な情報をとって利用されます。

例をみてみましょう。以下のようにgit credential fillと端末上で入力することで、Git-credentialの対話モードを開始することができます。

$ git credential fill
protocol=https
host=github.com

protocol=https
host=github.com
username=hal0taso
password=PASSWORD

まず、Git-credentialは標準入力からの入力を待機します。ここでは現在わかっている情報である、プロトコル(https)とホスト名(github.com)を入力します。空白行を渡すことでGit-credentialに入力が完了したことを知らせます。すると、その入力にヒットした内容が標準出力に表示されます。

この情報を渡すことによって、ユーザーは認証情報を入力する必要がなくなります。

より詳しい解説はGitの以下のページにあるので、そちらを読んでみることをおすすめします。

Git - 認証情報の保存

参考

Git - Credential Storage

Updating credentials from the OSX Keychain - User Documentation

git - githubへgit pushしようとすると403エラーとなる - スタック・オーバーフロー

osx - How do you reset the stored credentials in 'git credential-osxkeychain'? - Stack Overflow

Gitで有効な設定を確認したい - Qiita