short-d/short

View on GitHub
backend/app/adapter/facebook/identityprovider.go

Summary

Maintainability
A
0 mins
Test Coverage
package facebook

import (
    "net/http"
    "net/url"

    "github.com/short-d/app/fw/webreq"
    "github.com/short-d/short/backend/app/usecase/sso"
)

// More info here: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow

const (
    fbAuthorizationAPI = "https://www.facebook.com/v4.0/dialog/oauth"
    fbAccessTokenAPI   = "https://graph.facebook.com/v4.0/oauth/access_token"
    fbScopes           = "public_profile,email"
    fbResponseType     = "code"
)

var _ sso.IdentityProvider = (*IdentityProvider)(nil)

// IdentityProvider represents Facebook OAuth service.
type IdentityProvider struct {
    clientID     string
    clientSecret string
    httpRequest  webreq.HTTP
    redirectURI  string
}

// GetAuthorizationURL retrieves the URL of Facebook sign in page.
func (g IdentityProvider) GetAuthorizationURL() string {
    clientID := g.clientID
    redirectURI := g.redirectURI
    responseType := fbResponseType
    scope := fbScopes

    u, err := url.Parse(fbAuthorizationAPI)
    if err != nil {
        return ""
    }

    query := u.Query()
    query.Set("client_id", clientID)
    query.Set("redirect_uri", redirectURI)
    query.Set("scope", scope)
    query.Set("response_type", responseType)
    u.RawQuery = query.Encode()

    return u.String()
}

// RequestAccessToken retrieves access token of user's Facebook account using
// authorization code.
func (g IdentityProvider) RequestAccessToken(authorizationCode string) (accessToken string, err error) {
    type fbAccessTokenResponse struct {
        AccessToken string `json:"access_token"`
        TokenType   string `json:"token_type"`
        ExpiresIn   int    `json:"expires_in"`
    }

    clientID := g.clientID
    clientSecret := g.clientSecret
    redirectURI := g.redirectURI

    u, err := url.Parse(fbAccessTokenAPI)
    if err != nil {
        return "", err
    }

    query := url.Values{}
    query.Set("client_id", clientID)
    query.Set("redirect_uri", redirectURI)
    query.Set("client_secret", clientSecret)
    query.Set("code", authorizationCode)
    u.RawQuery = query.Encode()

    apiRes := fbAccessTokenResponse{}
    err = g.httpRequest.JSON(http.MethodPost, u.String(), map[string]string{}, "", &apiRes)

    if err != nil {
        return "", err
    }

    return apiRes.AccessToken, nil
}

// NewIdentityProvider initializes Facebook OAuth service.
func NewIdentityProvider(
    httpRequest webreq.HTTP,
    clientID string,
    clientSecret string,
    redirectURI string,
) IdentityProvider {
    return IdentityProvider{
        clientID:     clientID,
        clientSecret: clientSecret,
        httpRequest:  httpRequest,
        redirectURI:  redirectURI,
    }
}