はじめに
GithubのOIDCを実装したかったんだけど、ちょっとチュートリアルを見つけたのでそれをパットやってみる。
今回やるのはこれ
実装
GitHubAppの登録
まずはGithubで準備することがある。
- GithubAppsの設定ページにアクセス
- [New GitHub App] をクリック
- 認証をする
- 必要な情報を入力する
- 作成完了
Rubyの開発環境整え
参考はこちら
まずは以下のファイルを準備
- .gitignore
- Gemfile
- Gemfile.lock
- docker-compose.yaml
- Dockerfile
- app.rb
コマンドで1.2.3.のファイルを準備
# gitignoreをダウンロード $ curl https://raw.githubusercontent.com/github/gitignore/master/Ruby.gitignore -o .gitignore # GemfileとGemfile.lockを生成とダウンロード $ docker run --rm --volume $(pwd):/app --workdir /app ruby:2.7-slim bundle init $ docker run --rm --volume $(pwd):/app --workdir /app ruby:2.7-slim bundle add sinatra $ docker run --rm --volume $(pwd):/app --workdir /app ruby:2.7-slim bundle add dotenv
手動でDockerfileとdocker-compose.yamlを作成
rubyは/app
ディレクトリを使うのが一般的なのか?まぁとりあえず従いますよ。
FROM ruby:2.7-slim WORKDIR /app COPY Gemfile ./ COPY Gemfile.lock ./ RUN bundle config --local set path 'vendor/bundle' RUN bundle install CMD bundle exec ruby app.rb
version: '3' services: app: build: . volumes: - .:/app - /app/vendor/bundle ports: - 4567:4567
app.rb (アプリ自体のファイル) を作成
まぁ作成
require 'sinatra' configure do set :bind, '0.0.0.0' end get '/' do 'Hello Sinatra!' end
起動
まぁ、ついたね。
OIDCの設定を進める
- GitHub Appsの設定ページを開く
- [Edit] を押す
- [Generate a new client secret] で新しいクライアントシークレットを発行する。
- クライアントIDと発行されたクライアントシークレットを
.env
に保存する - gitignoreに.envを追加
CLIENT_ID="YOUR_CLIENT_ID" CLIENT_SECRET="YOUR_CLIENT_SECRET"
- # .env + .env
ログインボタンを設置
app.rbに以下の記述をして、Loginボタンを設置します。
require "sinatra" require "dotenv/load" require "net/http" require "json" CLIENT_ID = ENV.fetch("CLIENT_ID") CLIENT_SECRET = ENV.fetch("CLIENT_SECRET") configure do set :bind, '0.0.0.0' end get "/" do link = '<a href="https://github.com/login/oauth/authorize?client_id=<%= CLIENT_ID %>">Login with GitHub</a>' erb link end
linkをクリックすると、Callback先を指定してないので、こうなる。
Callbackを設定
sinatraでCallbackURLを設定
以下を追記
+ get "/github/callback" do + code = params["code"] + render = "Successfully authorized! Got code #{code}." + erb render + end
Githubに設定
GitHubAppの設定編集に行き、[Callback URL]を編集。
僕の場合は、http://localhost:4567/github/callback
と入力
保存も忘れずに
やってみる
いいね、ちゃんとcode
も受け取れる。
access_tokenを受け取る
先程もらった、code
をもとに、access_token
をもらいにいこう。
以下を追記した。
追記した内容は、
parse_response
関数で、GitHub API からの応答を解析します。exchange_code
関数で、code
パラメーターをユーザー アクセス トークンと交換します。- コールバック URL 要求のハンドラーで
exchange_code
を呼び出して、code
パラメーターをユーザー アクセス トークンと交換するようになります。 - コールバック ページに、トークンが生成されたことを示すテキストが表示されるようになります。 トークン生成が成功しなかった場合は、ページにそのエラーが示されます。
def parse_response(response) case response when Net::HTTPOK JSON.parse(response.body) else puts response puts response.body {} end end def exchange_code(code) params = { "client_id" => CLIENT_ID, "client_secret" => CLIENT_SECRET, "code" => code } result = Net::HTTP.post( URI("https://github.com/login/oauth/access_token"), URI.encode_www_form(params), {"Accept" => "application/json"} ) parse_response(result) end get "/github/callback" do code = params["code"] token_data = exchange_code(code) if token_data.key?("access_token") token = token_data["access_token"] render = "Successfully authorized! Got code #{code} and exchanged it for a user access token ending in #{token[-9..-1]}." erb render else render = "Authorized, but unable to exchange code #{code} for token." erb render end end
じゃあこれでやってみると、ちゃんと受け取れる!
access_tokenを使って、REST APIを叩く。
じゃあついにaccess_tokenを得ることができたので、REST APIを叩いてみよう。
Githubの設定変更
いつものようにGithubAppsを変更する。
- GithubAppsの設定ページにいき、[Edit]を押す
- 左のサイドバーの[Permissions & events]をクリック
- Repository permissionsの Administration と Contents をRead-onlyに変更する
- 保存
app.rbの修正
以下を追記して、修正
def get_repos(token) uri = URI("https://api.github.com/user/repos") result = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| body = {"access_token" => token}.to_json auth = "Bearer #{token}" headers = {"Accept" => "application/json", "Content-Type" => "application/json", "Authorization" => auth} http.send_request("GET", uri.path, body, headers) end parse_response(result) end get "/github/callback" do code = params["code"] token_data = exchange_code(code) if token_data.key?("access_token") token = token_data["access_token"] repos = get_repos(token) render = "Successfully authorized! Welcome, #{repos})." erb render else render = "Authorized, but unable to exchange code #{code} for token." erb render end end
すると、callbackページで、レポジトリの一覧を取得することができるようになった。
だけど、これ、privateレポジトリの取得ができないっぽい? どうやら、このappをinstallしたレポジトリしかprivateに関しては取得できないらしい。
えーーーっと、やりたいことと違ったかな。?
次やりたいこと