go言語でOAuth2認証
最近,go言語でGithubとQiitaのOauth2認証を実装することがあったのでメモ書き程度に書いていきます.
OAuth2認証のフロー
OAuth2のフローは以下のようになっています(Githubの場合)
- Githubにコードをリクエスト
- あらかじめ指定しておいたページに自動でリダイレクト
- リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
- 3のレスポンスのbodyからアクセストークンを取得
- アクセストークンを使ってAPIを使用
ざっくりと以上のような流れで認証します.
Githubの場合
まず,Githubのアプリに登録します.
そこで得られたClientIDとClientSecretをメモなどして覚えておきましょう.
リダイレクト先のURLは自分のサイトの適当なURLを指定しましょう(例http://自分のサイトURL/oauth/callback)
- Githubにコードをリクエスト
- あらかじめ指定しておいたページに自動でリダイレクト
- リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
- 3のレスポンスのbodyからアクセストークンを取得
- アクセストークンを使ってAPIを使用
Githubアプリを登録したらまず,Githubの指定されたURL(https://github.com/login/oauth/authorize) に先ほど取得したClientIDをパラメータに指定してリダイレクトします.
実装は以下のようになります.なお,今回はgo言語のwebフレームワークginを使っています
func RedirectAuthrizeClient(c *gin.Context, clientID string) {
authURL := "https://github.com/login/oauth/authorize?client_id=" + clientID
c.Redirect(http.StatusMovedPermanently, authURL)
}
- Githubにコードをリクエスト
- あらかじめ指定しておいたページに自動でリダイレクト
- リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
- 3のレスポンスのbodyからアクセストークンを取得
- アクセストークンを使ってAPIを使用
次にGithubアプリを登録する際に指定したページに自動でリダイレクトされるのでそこでの処理を実装していきます.
type CredentialInfo struct {
AccessToken string `json:"access_token"`
Scope string `json:"scope"`
TokenType string `json:"token_type"`
}
func GetAccessTokenClient(c *gin.Context, clientID string, clientSecret string) (*CredentialInfo){
code := c.Request.URL.Query().Get("code")
state := c.Request.URL.Query().Get("state")
if state == "" {
fmt.Println("state is empty")
}
values := url.Values{}
values.Add("code", code)
values.Add("client_id", clientID)
values.Add("client_secret", clientSecret)
req, err := http.NewRequest(
"POST",
"https://github.com/login/oauth/access_token",
strings.NewReader(values.Encode()),
)
if err != nil {
panic(err)
}
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
byteArray, _ := ioutil.ReadAll(resp.Body)
var cre *CredentialInfo
json.Unmarshal(byteArray, &cre)
c.Redirect(http.StatusMovedPermanently, "/")
return
}
req.Header.Set("Accept", "application/json")
の部分はレスポンスのbodyの形式を指定していて,これを指定しないとレスポンスがjson形式で返ってきません.Githubでは
{
access_token: ***,
scope: ***,
token_type:"bearer"
}
の形式でレスポンスが返ってくるのでこの中のaccess_tokenを保存したり変数に格納などしてAPIを呼び出すときに使います.
- Githubにコードをリクエスト
- あらかじめ指定しておいたページに自動でリダイレクト
- リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
- 3のレスポンスのbodyからアクセストークンを取得
- アクセストークンを使ってAPIを使用
あとは取得したアクセストークンをヘッダに含んでAPIを叩くだけです!