From fb2e3d3c0a148979d43549935f5e7eb6d484a203 Mon Sep 17 00:00:00 2001 From: Orkhan Mamedov Date: Sun, 26 Jan 2025 20:00:32 -0500 Subject: [PATCH 1/4] Use automatic oauth callback flow for linux --- oauth/oauth.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/oauth/oauth.go b/oauth/oauth.go index c554caa..addfc48 100644 --- a/oauth/oauth.go +++ b/oauth/oauth.go @@ -8,6 +8,7 @@ import ( "math/rand" "net/http" "net/url" + "os" "os/exec" "runtime" "strconv" @@ -58,11 +59,12 @@ type AuthenticateUserFuncConfig struct { // Initiate an *AuthorizedClient with a given APPKEY, SECRET // TODO: Include the user's given callback URL, as if someone wants to host off-prem they should be able to // TODO: Investigate the previous statement, localhost might work for any implementation? -func Initiate(APPKEY, SECRET string) *AuthorizedClient { +func Initiate(APPKEY, SECRET, CBURL string) *AuthorizedClient { conf := &oauth2.Config{ ClientID: APPKEY, // Schwab App Key ClientSecret: SECRET, // Schwab App Secret + RedirectURL: CBURL, Endpoint: oauth2.Endpoint{ AuthURL: "https://api.schwabapi.com/v1/oauth/authorize", @@ -129,7 +131,8 @@ func authenticateUser(oauthConfig *oauth2.Config, options ...AuthenticateUserOpt // Redirect user to consent page to ask for permission // for the scopes specified above. - oauthConfig.RedirectURL = fmt.Sprintf("https://%s", IP) + oauthConfig.RedirectURL = fmt.Sprintf(oauthConfig.RedirectURL) + // oauthConfig.RedirectURL = fmt.Sprintf("https://%s", IP) // Some random string, random for each request oauthStateString := randSeq(16) ctx = context.WithValue(ctx, oauthStateStringContextKey, oauthStateString) @@ -191,7 +194,11 @@ func startHTTPServer(ctx context.Context, conf *oauth2.Config) (clientChan chan http.HandleFunc("/", callbackHandler(ctx, conf, clientChan)) - srv := &http.Server{} + addr, ok := os.LookupEnv("OAUTH_CALLBACK_ADDR") + if !ok { + addr = "127.0.0.1:443" + } + srv := &http.Server{Addr: addr} // handle server shutdown signal go func() { @@ -227,9 +234,11 @@ func callbackHandler(ctx context.Context, oauthConfig *oauth2.Config, clientChan return func(w http.ResponseWriter, r *http.Request) { requestStateString := ctx.Value(oauthStateStringContextKey).(string) responseStateString := r.FormValue("state") + // if the response state doesn not match the request state, return an error if responseStateString != requestStateString { fmt.Printf("invalid oauth state, expected '%s', got '%s'\n", requestStateString, responseStateString) - http.Redirect(w, r, "/", http.StatusTemporaryRedirect) + w.Write([]byte(fmt.Sprintf("invalid oauth state, expected '%s', got '%s'", requestStateString, responseStateString))) + w.WriteHeader(http.StatusBadRequest) return } @@ -237,9 +246,11 @@ func callbackHandler(ctx context.Context, oauthConfig *oauth2.Config, clientChan token, err := oauthConfig.Exchange(ctx, code) if err != nil { fmt.Printf("oauthoauthConfig.Exchange() failed with '%s'\n", err) - http.Redirect(w, r, "/", http.StatusTemporaryRedirect) + w.Write([]byte(fmt.Sprintf("oauthoauthConfig.Exchange() failed with '%s'\n", err))) + w.WriteHeader(http.StatusBadRequest) return } + log.Printf(fmt.Sprintf("Access token: %s", token.AccessToken)) // The HTTP Client returned by oauthConfig.Client will refresh the token as necessary client := &AuthorizedClient{ oauthConfig.Client(ctx, token), From d20f89f534edc4aa05ef44f8d57c71a09506231b Mon Sep 17 00:00:00 2001 From: Orkhan Mamedov Date: Sun, 26 Jan 2025 20:35:28 -0500 Subject: [PATCH 2/4] Remove TODOs, we're now passing the CBURL to the library --- oauth/oauth.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/oauth/oauth.go b/oauth/oauth.go index addfc48..6ca70ba 100644 --- a/oauth/oauth.go +++ b/oauth/oauth.go @@ -57,8 +57,6 @@ type AuthenticateUserFuncConfig struct { } // Initiate an *AuthorizedClient with a given APPKEY, SECRET -// TODO: Include the user's given callback URL, as if someone wants to host off-prem they should be able to -// TODO: Investigate the previous statement, localhost might work for any implementation? func Initiate(APPKEY, SECRET, CBURL string) *AuthorizedClient { conf := &oauth2.Config{ From 7d22303ab766f5ebaa5c2b5b9135cfe1b976bb13 Mon Sep 17 00:00:00 2001 From: Orkhan Mamedov Date: Tue, 28 Jan 2025 23:17:13 -0500 Subject: [PATCH 3/4] Remove garbage --- oauth/oauth.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/oauth/oauth.go b/oauth/oauth.go index 6ca70ba..8744b66 100644 --- a/oauth/oauth.go +++ b/oauth/oauth.go @@ -127,10 +127,6 @@ func authenticateUser(oauthConfig *oauth2.Config, options ...AuthenticateUserOpt sslcli := &http.Client{Transport: tr} ctx := context.WithValue(context.Background(), oauth2.HTTPClient, sslcli) - // Redirect user to consent page to ask for permission - // for the scopes specified above. - oauthConfig.RedirectURL = fmt.Sprintf(oauthConfig.RedirectURL) - // oauthConfig.RedirectURL = fmt.Sprintf("https://%s", IP) // Some random string, random for each request oauthStateString := randSeq(16) ctx = context.WithValue(ctx, oauthStateStringContextKey, oauthStateString) From 8af33bd47435d3aec8fb26e38a466525adc8ca90 Mon Sep 17 00:00:00 2001 From: Orkhan Mamedov Date: Sat, 15 Feb 2025 22:24:28 -0500 Subject: [PATCH 4/4] remove log --- oauth/oauth.go | 1 - 1 file changed, 1 deletion(-) diff --git a/oauth/oauth.go b/oauth/oauth.go index 8744b66..c425da9 100644 --- a/oauth/oauth.go +++ b/oauth/oauth.go @@ -244,7 +244,6 @@ func callbackHandler(ctx context.Context, oauthConfig *oauth2.Config, clientChan w.WriteHeader(http.StatusBadRequest) return } - log.Printf(fmt.Sprintf("Access token: %s", token.AccessToken)) // The HTTP Client returned by oauthConfig.Client will refresh the token as necessary client := &AuthorizedClient{ oauthConfig.Client(ctx, token),