Help us understand the problem. What is going on with this article?

go言語でOAuth2認証を実装

More than 1 year has passed since last update.

go言語でOAuth2認証

最近,go言語でGithubとQiitaのOauth2認証を実装することがあったのでメモ書き程度に書いていきます.

OAuth2認証のフロー

OAuth2のフローは以下のようになっています(Githubの場合)

  1. Githubにコードをリクエスト
  2. あらかじめ指定しておいたページに自動でリダイレクト
  3. リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
  4. 3のレスポンスのbodyからアクセストークンを取得
  5. アクセストークンを使ってAPIを使用

ざっくりと以上のような流れで認証します.

Githubの場合

まず,Githubのアプリに登録します.
そこで得られたClientIDとClientSecretをメモなどして覚えておきましょう.
リダイレクト先のURLは自分のサイトの適当なURLを指定しましょう(例http://自分のサイトURL/oauth/callback)

  1. Githubにコードをリクエスト
  2. あらかじめ指定しておいたページに自動でリダイレクト
  3. リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
  4. 3のレスポンスのbodyからアクセストークンを取得
  5. アクセストークンを使って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)
}

  1. Githubにコードをリクエスト
  2. あらかじめ指定しておいたページに自動でリダイレクト
  3. リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
  4. 3のレスポンスのbodyからアクセストークンを取得
  5. アクセストークンを使って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を呼び出すときに使います.

  1. Githubにコードをリクエスト
  2. あらかじめ指定しておいたページに自動でリダイレクト
  3. リダイレクト時にURLにパラメータで渡されたcodeを使ってアクセストークンをリクエスト
  4. 3のレスポンスのbodyからアクセストークンを取得
  5. アクセストークンを使ってAPIを使用

あとは取得したアクセストークンをヘッダに含んでAPIを叩くだけです!

gittokkunn
趣味でWebアプリ開発をしています
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away