ลองทำ LINE Login ด้วย Line Oauth


Oauth คือไร

อ่านได้จากที่นี้

เรียนรู้ OAuth


Create line provider

https://developers.line.biz/console/

a

a

  • tab LINE Login ใส่ Callback URL

a

a

  • ดู document ที่ทาง LINE มีให้

ในที่นี้ เลือกเป็น LINE Login v2.1

https://developers.line.biz/en/reference/line-login/

https://developers.line.biz/en/docs/line-login/integrate-line-login/

Step ขอ Authorization Code

  • เปิดไปที่ URL
# example
https://access.line.me/oauth2/v2.1/authorize \
?response_type=code \
&client_id={client_id || channel_id } \
&redirect_uri={callback_url} \
&state=xxx \
&scope=profile openid

parameter

  • response_type
  • client_id
  • state
  • scope

a

a

จะได้ authorization code มาในรูปแบบ query string ตอบกับมาที่ callback_url ที่เรากำหนดไป

ทดสอบยิงไปหา Line เพื่อขอ Access Token สำหรับขอข้อมูล profile


# example
curl -X POST https://api.line.me/oauth2/v2.1/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=authorization_code' \
-d 'code=xxx' \
-d 'redirect_uri=xxx' \
-d 'client_id=xxx' \
-d 'client_secret=xxx'

parameter

  • grant_type
  • code
  • redirect_uri
  • client_id
  • client_secret

a

เอา Access Token ที่ได้มาไป Get UserInfo

# example
curl -X GET https://api.line.me/v2/profile \
-H 'Authorization: Bearer {access token}'

a


ทดสอบทำ Api จาก Flow ด้านบน

"github.com/labstack/echo/v4"
  • .env
CLIENT_ID=xxx
CLIENT_SECRET=xxx
  • main.go
package main

import (
	"net/http"
	
	"github.com/labstack/echo/v4"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.JSON(http.StatusOK, map[string]string{"message": "hello"})
	})
	e.Logger.Fatal(e.Start(":1323"))
}
  • ส่วนของการขอ Authorization code
e.GET("/oauth/line", func(c echo.Context) error {
		clientID := os.Getenv("CLIENT_ID")
		callbackURL := "http://localhost:1323"
		uri := fmt.Sprintf("https://access.line.me/oauth2/v2.1/authorize?response_type=code&state=xxx&client_id=%s&redirect_uri=%s&scope=profile openid", clientID, callbackURL)
		return c.Redirect(http.StatusPermanentRedirect, uri)
})
  • ส่วนของการ ยิงไปหา Line เพื่อขอ Access Token สำหรับขอข้อมูล profile
e.POST("/oauth/line/token", func(c echo.Context) error {
	var uri = "https://api.line.me/oauth2/v2.1/token"
	data := url.Values{}
	data.Set("grant_type", "authorization_code")
	data.Set("code", c.FormValue("code"))
	data.Set("redirect_uri", "http://localhost:1323")
	data.Set("client_id", os.Getenv("CLIENT_ID"))
	data.Set("client_secret", os.Getenv("CLIENT_SECRET"))
	req, err := http.NewRequest("POST", uri, strings.NewReader(data.Encode()))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	/// http client end ///
	var res map[string]interface{}

	json.NewDecoder(resp.Body).Decode(&res)
	return c.JSON(resp.StatusCode, res)
})

a

  • ส่วนของการเอา Access Token ไปขอข้อมูล UserInfo
e.POST("/oauth/line/getInfo", func(c echo.Context) error {
	uri := "https://api.line.me/v2/profile"
	req, err := http.NewRequest("GET", uri, nil)
	req.Header.Set("Authorization", "Bearer "+c.Request().Header.Get("Authorization"))
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	/// http client end ///
	var res map[string]interface{}

	json.NewDecoder(resp.Body).Decode(&res)
	return c.JSON(resp.StatusCode, res)
})

a

  • main.go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"strings"

	_ "github.com/joho/godotenv/autoload"
	"github.com/labstack/echo/v4"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.JSON(http.StatusOK, map[string]string{"message": "hello"})
	})
	e.GET("/oauth/line", func(c echo.Context) error {
		clientID := os.Getenv("CLIENT_ID")
		callbackURL := "http://localhost:1323"
		uri := fmt.Sprintf("https://access.line.me/oauth2/v2.1/authorize?response_type=code&state=xxx&client_id=%s&redirect_uri=%s&scope=profile openid", clientID, callbackURL)
		return c.Redirect(http.StatusPermanentRedirect, uri)
	})

	e.POST("/oauth/line/token", func(c echo.Context) error {
		var uri = "https://api.line.me/oauth2/v2.1/token"
		data := url.Values{}
		data.Set("grant_type", "authorization_code")
		data.Set("code", c.FormValue("code"))
		data.Set("redirect_uri", "http://localhost:1323")
		data.Set("client_id", os.Getenv("CLIENT_ID"))
		data.Set("client_secret", os.Getenv("CLIENT_SECRET"))
		req, err := http.NewRequest("POST", uri, strings.NewReader(data.Encode()))
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
		client := &http.Client{}
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		defer resp.Body.Close()
		/// http client end ///
		var res map[string]interface{}

		json.NewDecoder(resp.Body).Decode(&res)
		return c.JSON(resp.StatusCode, res)
	})
	e.POST("/oauth/line/getInfo", func(c echo.Context) error {
		uri := "https://api.line.me/v2/profile"
		req, err := http.NewRequest("GET", uri, nil)
		req.Header.Set("Authorization", "Bearer "+c.Request().Header.Get("Authorization"))
		client := &http.Client{}
		resp, err := client.Do(req)
		if err != nil {
			panic(err)
		}
		defer resp.Body.Close()
		/// http client end ///
		var res map[string]interface{}

		json.NewDecoder(resp.Body).Decode(&res)
		return c.JSON(resp.StatusCode, res)
	})
	e.Logger.Fatal(e.Start(":1323"))
}

source code https://github.com/jaedsadadotme/line-oauth


ref :

https://developers.line.biz/en/reference/line-login/ https://developers.line.biz/en/docs/line-login/integrate-line-login/