feat: Adds login via twitter

This commit is contained in:
szczepad
2022-08-14 20:19:48 +02:00
parent aa232de426
commit f73d1fc588
5 changed files with 126 additions and 6 deletions

View File

@@ -68,7 +68,7 @@ func OAuthCallbackHandler() gin.HandlerFunc {
case constants.AuthRecipeMethodApple:
user, err = processAppleUserInfo(code)
case constants.AuthRecipeMethodTwitter:
user, err = processTwitterUserInfo(code)
user, err = processTwitterUserInfo(code, sessionState)
default:
log.Info("Invalid oauth provider")
err = fmt.Errorf(`invalid oauth provider`)
@@ -567,8 +567,69 @@ func processAppleUserInfo(code string) (models.User, error) {
return user, err
}
func processTwitterUserInfo(code string) (models.User, error) {
func processTwitterUserInfo(code, verifier string) (models.User, error) {
user := models.User{}
// TODO exchange code and get user information
oauth2Token, err := oauth.OAuthProviders.TwitterConfig.Exchange(oauth2.NoContext, code, oauth2.SetAuthURLParam("code_verifier", verifier))
if err != nil {
log.Debug("Failed to exchange code for token: ", err)
return user, fmt.Errorf("invalid twitter exchange code: %s", err.Error())
}
client := http.Client{}
req, err := http.NewRequest("GET", constants.TwitterUserInfoURL, nil)
if err != nil {
log.Debug("Failed to create Twitter user info request: ", err)
return user, fmt.Errorf("error creating Twitter user info request: %s", err.Error())
}
req.Header = http.Header{
"Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)},
}
response, err := client.Do(req)
if err != nil {
log.Debug("Failed to request Twitter user info: ", err)
return user, err
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Debug("Failed to read Twitter user info response body: ", err)
return user, fmt.Errorf("failed to read Twitter response body: %s", err.Error())
}
if response.StatusCode >= 400 {
log.Debug("Failed to request Twitter user info: ", string(body))
return user, fmt.Errorf("failed to request Twitter user info: %s", string(body))
}
responseRawData := make(map[string]interface{})
json.Unmarshal(body, &responseRawData)
userRawData := responseRawData["data"].(map[string]interface{})
log.Info(userRawData)
// Twitter API does not return E-Mail adresses by default. For that case special privileges have
// 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
// Currently Twitter API only provides the full name of a user. To fill givenName and familyName
// the full name will be split at the first whitespace. This approach will not be valid for all name combinations
nameArr := strings.SplitAfterN(userRawData["name"].(string), " ", 2)
firstName := nameArr[0]
lastName := ""
if len(nameArr) == 2 {
lastName = nameArr[1]
}
nickname := userRawData["username"].(string)
profilePicture := userRawData["profile_image_url"].(string)
user = models.User{
GivenName: &firstName,
FamilyName: &lastName,
Picture: &profilePicture,
Nickname: &nickname,
}
return user, nil
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/authorizerdev/authorizer/server/memorystore"
"github.com/authorizerdev/authorizer/server/oauth"
"github.com/authorizerdev/authorizer/server/parsers"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/authorizerdev/authorizer/server/validators"
)
@@ -175,7 +176,10 @@ func OAuthLoginHandler() gin.HandlerFunc {
isProviderConfigured = false
break
}
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodTwitter)
verifier, challenge := utils.GenerateCodeChallenge()
err := memorystore.Provider.SetState(oauthStateString, verifier)
if err != nil {
log.Debug("Error setting state: ", err)
c.JSON(500, gin.H{
@@ -184,7 +188,7 @@ func OAuthLoginHandler() gin.HandlerFunc {
return
}
oauth.OAuthProviders.TwitterConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitter
url := oauth.OAuthProviders.TwitterConfig.AuthCodeURL(oauthStateString)
url := oauth.OAuthProviders.TwitterConfig.AuthCodeURL(oauthStateString, oauth2.SetAuthURLParam("code_challenge", challenge), oauth2.SetAuthURLParam("code_challenge_method", "S256"))
c.Redirect(http.StatusTemporaryRedirect, url)
case constants.AuthRecipeMethodApple:
if oauth.OAuthProviders.AppleConfig == nil {