@@ -68,7 +68,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
6868 case constants .AuthRecipeMethodApple :
6969 user , err = processAppleUserInfo (code )
7070 case constants .AuthRecipeMethodTwitter :
71- user , err = processTwitterUserInfo (code )
71+ user , err = processTwitterUserInfo (code , sessionState )
7272 default :
7373 log .Info ("Invalid oauth provider" )
7474 err = fmt .Errorf (`invalid oauth provider` )
@@ -567,8 +567,69 @@ func processAppleUserInfo(code string) (models.User, error) {
567567 return user , err
568568}
569569
570- func processTwitterUserInfo (code string ) (models.User , error ) {
570+ func processTwitterUserInfo (code , verifier string ) (models.User , error ) {
571571 user := models.User {}
572- // TODO exchange code and get user information
572+ oauth2Token , err := oauth .OAuthProviders .TwitterConfig .Exchange (oauth2 .NoContext , code , oauth2 .SetAuthURLParam ("code_verifier" , verifier ))
573+ if err != nil {
574+ log .Debug ("Failed to exchange code for token: " , err )
575+ return user , fmt .Errorf ("invalid twitter exchange code: %s" , err .Error ())
576+ }
577+
578+ client := http.Client {}
579+ req , err := http .NewRequest ("GET" , constants .TwitterUserInfoURL , nil )
580+ if err != nil {
581+ log .Debug ("Failed to create Twitter user info request: " , err )
582+ return user , fmt .Errorf ("error creating Twitter user info request: %s" , err .Error ())
583+ }
584+ req .Header = http.Header {
585+ "Authorization" : []string {fmt .Sprintf ("Bearer %s" , oauth2Token .AccessToken )},
586+ }
587+
588+ response , err := client .Do (req )
589+ if err != nil {
590+ log .Debug ("Failed to request Twitter user info: " , err )
591+ return user , err
592+ }
593+
594+ defer response .Body .Close ()
595+ body , err := ioutil .ReadAll (response .Body )
596+ if err != nil {
597+ log .Debug ("Failed to read Twitter user info response body: " , err )
598+ return user , fmt .Errorf ("failed to read Twitter response body: %s" , err .Error ())
599+ }
600+
601+ if response .StatusCode >= 400 {
602+ log .Debug ("Failed to request Twitter user info: " , string (body ))
603+ return user , fmt .Errorf ("failed to request Twitter user info: %s" , string (body ))
604+ }
605+
606+ responseRawData := make (map [string ]interface {})
607+ json .Unmarshal (body , & responseRawData )
608+
609+ userRawData := responseRawData ["data" ].(map [string ]interface {})
610+
611+ log .Info (userRawData )
612+ // Twitter API does not return E-Mail adresses by default. For that case special privileges have
613+ // to be granted on a per-App basis. See https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials
614+
615+ // Currently Twitter API only provides the full name of a user. To fill givenName and familyName
616+ // the full name will be split at the first whitespace. This approach will not be valid for all name combinations
617+ nameArr := strings .SplitAfterN (userRawData ["name" ].(string ), " " , 2 )
618+
619+ firstName := nameArr [0 ]
620+ lastName := ""
621+ if len (nameArr ) == 2 {
622+ lastName = nameArr [1 ]
623+ }
624+ nickname := userRawData ["username" ].(string )
625+ profilePicture := userRawData ["profile_image_url" ].(string )
626+
627+ user = models.User {
628+ GivenName : & firstName ,
629+ FamilyName : & lastName ,
630+ Picture : & profilePicture ,
631+ Nickname : & nickname ,
632+ }
633+
573634 return user , nil
574635}
0 commit comments