88 "fmt"
99 "io/ioutil"
1010 "net/http"
11+ "time"
1112
13+ "github.com/golang-jwt/jwt/v4"
1214 "github.com/markbates/goth"
1315 "golang.org/x/oauth2"
1416)
@@ -17,8 +19,14 @@ const (
1719 authURL string = "https://access.line.me/oauth2/v2.1/authorize"
1820 tokenURL string = "https://api.line.me/oauth2/v2.1/token"
1921 endpointUser string = "https://api.line.me/v2/profile"
22+ issuerURL string = "https://access.line.me"
2023)
2124
25+ type IDTokenClaims struct {
26+ jwt.StandardClaims
27+ Email string `json:"email"`
28+ }
29+
2230// Provider is the implementation of `goth.Provider` for accessing Line.me.
2331type Provider struct {
2432 ClientKey string
@@ -95,11 +103,9 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
95103
96104 response , err := c .Do (req )
97105 if err != nil {
98- if response != nil {
99- response .Body .Close ()
100- }
101106 return user , err
102107 }
108+ defer response .Body .Close ()
103109
104110 if response .StatusCode != http .StatusOK {
105111 return user , fmt .Errorf ("%s responded with a %d trying to fetch user information" , p .providerName , response .StatusCode )
@@ -125,6 +131,13 @@ func (p *Provider) FetchUser(session goth.Session) (goth.User, error) {
125131 user .NickName = u .DisplayName
126132 user .AvatarURL = u .PictureURL
127133 user .UserID = u .UserID
134+
135+ if sess .IDToken != "" {
136+ if err = p .addDataFromIdToken (sess .IDToken , & user ); err != nil {
137+ return user , err
138+ }
139+ }
140+
128141 return user , err
129142}
130143
@@ -141,9 +154,7 @@ func newConfig(provider *Provider, scopes []string) *oauth2.Config {
141154 }
142155
143156 if len (scopes ) > 0 {
144- for _ , scope := range scopes {
145- c .Scopes = append (c .Scopes , scope )
146- }
157+ c .Scopes = append (c .Scopes , scopes ... )
147158 }
148159 return c
149160}
@@ -167,3 +178,36 @@ func (p *Provider) SetBotPrompt(botPrompt string) {
167178 }
168179 p .authCodeOptions = append (p .authCodeOptions , oauth2 .SetAuthURLParam ("bot_prompt" , botPrompt ))
169180}
181+
182+ func (p * Provider ) addDataFromIdToken (idToken string , user * goth.User ) error {
183+ token , err := jwt .ParseWithClaims (idToken , & IDTokenClaims {}, func (t * jwt.Token ) (interface {}, error ) {
184+ claims := t .Claims .(* IDTokenClaims )
185+ vErr := new (jwt.ValidationError )
186+
187+ if ! claims .VerifyAudience (p .ClientKey , true ) {
188+ vErr .Inner = fmt .Errorf ("audience is incorrect" )
189+ vErr .Errors |= jwt .ValidationErrorAudience
190+ }
191+ if ! claims .VerifyIssuer (issuerURL , true ) {
192+ vErr .Inner = fmt .Errorf ("issuer is incorrect" )
193+ vErr .Errors |= jwt .ValidationErrorIssuer
194+ }
195+ if ! claims .VerifyExpiresAt (time .Now ().Unix (), true ) {
196+ vErr .Inner = fmt .Errorf ("token is expired" )
197+ vErr .Errors |= jwt .ValidationErrorExpired
198+ }
199+ if vErr .Errors > 0 {
200+ return nil , vErr
201+ }
202+
203+ return []byte (p .Secret ), nil
204+ })
205+
206+ if err != nil {
207+ return err
208+ }
209+
210+ user .Email = token .Claims .(* IDTokenClaims ).Email
211+
212+ return nil
213+ }
0 commit comments