summaryrefslogtreecommitdiff
path: root/internal/platforms/linkedin/oauth2
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2024-10-08 11:00:32 +0300
committerPaul Buetow <paul@buetow.org>2024-10-08 11:00:32 +0300
commit8e30ad597bf200c2f3be22262364a6f4e1af1a36 (patch)
tree3eea2d66f09ad5f73ee9a65cc1077162820b335b /internal/platforms/linkedin/oauth2
parent2bc4585db96da4000fbf727beadfc25af64bcd4a (diff)
more on the linkedin oauth refactoring. need to test the changes, though.
Diffstat (limited to 'internal/platforms/linkedin/oauth2')
-rw-r--r--internal/platforms/linkedin/oauth2/oauth2.go121
1 files changed, 121 insertions, 0 deletions
diff --git a/internal/platforms/linkedin/oauth2/oauth2.go b/internal/platforms/linkedin/oauth2/oauth2.go
new file mode 100644
index 0000000..6a692b3
--- /dev/null
+++ b/internal/platforms/linkedin/oauth2/oauth2.go
@@ -0,0 +1,121 @@
+package oauth2
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+
+ "codeberg.org/snonux/gos/internal/config"
+ "golang.org/x/oauth2"
+ "golang.org/x/oauth2/linkedin"
+)
+
+var (
+ oauthConfig *oauth2.Config
+ oauthAccessToken string
+ oauthPersonID string
+ errCh chan error
+)
+
+func getOauthPersonID(token *oauth2.Token) (string, error) {
+ const url = "https://api.linkedin.com/v2/userinfo"
+
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return "", fmt.Errorf("Error creating request:%w", err)
+ }
+
+ req.Header.Set("Authorization", "Bearer "+token.AccessToken)
+ req.Header.Set("X-RestLi-Protocol-Version", "2.0.0")
+
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ return "", fmt.Errorf("Error making the request:%w", err)
+ }
+ defer resp.Body.Close()
+
+ body, _ := io.ReadAll(resp.Body)
+ if resp.StatusCode != http.StatusOK {
+ return "", fmt.Errorf("Failed to retrieve user profile. Status: %s\n%s\n", resp.Status, string(body))
+ }
+
+ type User struct {
+ Sub string `json:"sub"`
+ }
+ var user User
+ if err := json.Unmarshal(body, &user); err != nil {
+ return "", fmt.Errorf("Error unmarshalling JSON: %w", err)
+ }
+
+ return user.Sub, nil
+}
+
+func oauthIndexHandler(w http.ResponseWriter, r *http.Request) {
+ url := oauthConfig.AuthCodeURL("state", oauth2.AccessTypeOffline)
+ http.Redirect(w, r, url, http.StatusTemporaryRedirect)
+}
+
+func oauthCallbackHandler(w http.ResponseWriter, r *http.Request) {
+ defer close(errCh)
+ code := r.URL.Query().Get("code")
+
+ token, err := oauthConfig.Exchange(context.Background(), code)
+ if err != nil {
+ _, _ = w.Write([]byte(err.Error()))
+ errCh <- err
+ return
+ }
+ oauthAccessToken = token.AccessToken
+ _, _ = w.Write([]byte("Successfully fetched LinkedIn access token\n"))
+
+ if oauthPersonID, err = getOauthPersonID(token); err != nil {
+ _, _ = w.Write([]byte(err.Error()))
+ errCh <- err
+ return
+ }
+ _, _ = w.Write([]byte("Successfully fetched LinkedIn person ID\n"))
+}
+
+func LinkedInOauth2Creds(args config.Args) (string, string, error) {
+ secrets := args.Secrets
+ if secrets.LinkedInAccessToken != "" && secrets.LinkedInPersonID != "" {
+ // TODO: Check, whether the access token is still valid. If not, get a new one.
+ return secrets.LinkedInPersonID, secrets.MastodonAccessToken, nil
+ }
+
+ oauthConfig = &oauth2.Config{
+ ClientID: secrets.LinkedInClientID,
+ ClientSecret: secrets.LinkedInSecret,
+ RedirectURL: secrets.LinkedInRedirectURL,
+ Scopes: []string{"openid", "profile", "w_member_social"},
+ Endpoint: linkedin.Endpoint,
+ }
+ errCh := make(chan error)
+
+ http.HandleFunc("/", oauthIndexHandler)
+ http.HandleFunc("/callback", oauthCallbackHandler)
+
+ go func() {
+ log.Println("Listening on http://localhost:8080 for LinkedIn oauth2")
+ if err := http.ListenAndServe(":8080", nil); err != nil {
+ errCh <- err
+ }
+ }()
+
+ var errs error
+ for err := range errCh {
+ errs = errors.Join(errs, err)
+ }
+ if errs != nil {
+ return "", "", errs
+ }
+
+ secrets.MastodonAccessToken = oauthAccessToken
+ secrets.LinkedInPersonID = oauthPersonID
+ return oauthPersonID, oauthAccessToken, secrets.WriteToDisk(args.SecretsConfigPath)
+}