[Go言語]LINE ログイン連携方法 メモ

## 概要

* Go言語でLINEログイン連携する方法についてメモする。

## LINEログイン シーケンス

* 以下のようなLINEログイン連携シーケンスをGo言語で実装する。

```mermaid
sequenceDiagram
    participant U/A as U/A
    participant WebApp as テスト用Webアプリケーション
    participant LINE as LINEログインサーバー
    participant ProfileAPI as LINEプロファイルAPI

    U/A->>WebApp: LINEでログインをクリック
    WebApp->>U/A: LINEログインサーバーの認可エンドポイントへリダイレクト
    U/A->>LINE: 認可エンドポイントにアクセスし、ログイン情報を入力
    LINE->>U/A: 認可コードとともにテスト用WebアプリケーションのリダイレクトURLへリダイレクト
    U/A->>WebApp: 認可コード
    WebApp->>LINE: 認可コードとクライアントシークレットを使用してアクセストークンを要求
    LINE->>WebApp: アクセストークンをレスポンス
    WebApp->>ProfileAPI: アクセストークンを使用してユーザー情報を要求
    ProfileAPI->>WebApp: ユーザー情報をレスポンス
    WebApp->>U/A: ユーザー情報を表示

```



### 事前準備

### ライブラリインストール

OAuth2.0 連携用ライブラリ

```shell
go get golang.org/x/oauth2
```

### LINEログインチャネル作成

「[ウェブアプリにLINEログインを組み込む](https://developers.line.biz/ja/docs/line-login/integrate-line-login/)」に従い、連携に必要な設定情報の登録、取得を行う。

### コード

* `main.go`
  * <localhost:8080>でテスト用Webアプリケーションを起動し、上記シーケンス処理を行う。
  * `LINE Channel Settings`に事前準備で取得した連携設定情報を入力する。

```go
package main

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
)

// LINE OAuth2.0 Endpoint
var endpoint = oauth2.Endpoint{
	AuthURL:  "https://access.line.me/oauth2/v2.1/authorize",
	TokenURL: "https://api.line.me/oauth2/v2.1/token",
}

// LINE Channel Settings
var (
	// Channel ID
	clientID = "YOUR_CHANNEL_ID"
	// Channel Secret
	clientSecret = "YOUR_CHANNEL_SECRET"
	// Redirection Endpoint
	redirectURL = "YOUR_CHANNEL_REDIRECT_URL"
	// CSRF Param
	state = GenerateState()
)

// OAuth2.0 Settings
var oauth2Config = &oauth2.Config{
	ClientID:     clientID,
	ClientSecret: clientSecret,
	RedirectURL:  redirectURL,
	Scopes:       []string{"profile", "openid"},
	Endpoint:     endpoint,
}

// UserInfo From LINE
type UserInfo struct {
	UserID      string `json:"userId"`
	DisplayName string `json:"displayName"`
	PictureURL  string `json:"pictureUrl"`
}

// Generate CSRF Param
func GenerateState() string {
	b := make([]byte, 32)
	if _, err := rand.Read(b); err != nil {
		return ""
	}
	// base64 Encoding
	return base64.URLEncoding.EncodeToString(b)
}

func main() {
	http.HandleFunc("/", handleMain)
	http.HandleFunc("/login", handleLogin)
	http.HandleFunc("/callback", handleCallback)

	fmt.Println("Test Server Activated :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func handleMain(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "<html><body><a href=\"/login\">LINE Login by Go Lang</a></body></html>")
}

func handleLogin(w http.ResponseWriter, r *http.Request) {
	url := oauth2Config.AuthCodeURL(state)
	http.Redirect(w, r, url, http.StatusFound)
}

func handleCallback(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("state") != state {
		http.Error(w, "State Check Failed", http.StatusBadRequest)
		return
	}
	// Call OAuth2.0 Token Endpoint
	token, err := oauth2Config.Exchange(oauth2.NoContext, r.FormValue("code"))
	if err != nil {
		http.Error(w, "Token Exchange Failed: "+err.Error(), http.StatusInternalServerError)
		return
	}

	// Call User Profile Endpoint
	client := oauth2Config.Client(context.Background(), token)
	resp, err := client.Get("https://api.line.me/v2/profile")
	if err != nil {
		http.Error(w, "Failed to get user info: "+err.Error(), http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		http.Error(w, "Failed to read user info: "+err.Error(), http.StatusInternalServerError)
		return
	}

	var userInfo UserInfo
	if err := json.Unmarshal(data, &userInfo); err != nil {
		http.Error(w, "Failed to parse user info: "+err.Error(), http.StatusInternalServerError)
		return
	}

	prettyJSON, err := json.MarshalIndent(userInfo, "", "    ")
	if err != nil {
		http.Error(w, "Failed to generate pretty JSON: "+err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "User Info: %s", string(prettyJSON))
}

```



## 動作確認

* 以下のコマンドを実行し、テスト用Webアプリケーションを起動する。

```shell
go run .\main.go
Test Server Activated :8080
```

* <http://localhost:8080>にアクセスする。

* 「LINE Login by Go Lang」をクリックし、LINEログインする。

* 以下のようなユーザー情報が表示されることを確認する。

  ```json
  User Info: {
      "userId": "xxx",
      "displayName": "XXX",
      "pictureUrl": "https://profile.line-scdn.net/xxx"
  }
  ```

  

## 参考情報

* [ウェブアプリにLINEログインを組み込む](https://developers.line.biz/ja/docs/line-login/integrate-line-login/)
* [OAuth2 for Go](https://pkg.go.dev/golang.org/x/oauth2)