diff options
Diffstat (limited to 'backend/auth/oauth.go')
| -rw-r--r-- | backend/auth/oauth.go | 70 |
1 files changed, 42 insertions, 28 deletions
diff --git a/backend/auth/oauth.go b/backend/auth/oauth.go index b217ad2..9be1da0 100644 --- a/backend/auth/oauth.go +++ b/backend/auth/oauth.go @@ -10,6 +10,7 @@ import ( "net/http" "net/url" "strings" + "time" ) type OAuthConfig struct { @@ -25,6 +26,7 @@ type OAuthState struct { PDS string AccessToken string RefreshToken string + ExpiresAt time.Time KeyPair *DPoPKeyPair } @@ -110,32 +112,16 @@ func BuildAuthorizationURL(metadata *OAuthMetadata, config *OAuthConfig, state, return metadata.AuthorizationEndpoint + "?" + params.Encode() } -func ExchangeCodeForTokens(pdsURL, code, verifier, backendURL string, keypair *DPoPKeyPair) (*TokenResponse, error) { - metadata, err := FetchOAuthMetadata(pdsURL) - if err != nil { - return nil, err - } - - data := url.Values{ - "grant_type": {"authorization_code"}, - "code": {code}, - "redirect_uri": {backendURL + "/api/callback"}, - "code_verifier": {verifier}, - "client_id": {backendURL + "/api/callback"}, - } - - fmt.Printf("Sending verifier: %s\n", verifier) - - dpopProof, err := keypair.GenerateDPoPProof("POST", metadata.TokenEndpoint, "") +func postWithDPoP(url string, data url.Values, keypair *DPoPKeyPair) (*TokenResponse, error) { + dpopProof, err := keypair.GenerateDPoPProof("POST", url, "") if err != nil { return nil, err } - req, err := http.NewRequest("POST", metadata.TokenEndpoint, strings.NewReader(data.Encode())) + req, err := http.NewRequest("POST", url, strings.NewReader(data.Encode())) if err != nil { return nil, err } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("DPoP", dpopProof) @@ -145,7 +131,6 @@ func ExchangeCodeForTokens(pdsURL, code, verifier, backendURL string, keypair *D } defer resp.Body.Close() - // if nonce required, retry with nonce if resp.StatusCode == 400 { body, _ := io.ReadAll(resp.Body) bodyStr := string(body) @@ -156,13 +141,12 @@ func ExchangeCodeForTokens(pdsURL, code, verifier, backendURL string, keypair *D return nil, fmt.Errorf("server requires nonce but didn't provide one") } - // generate new DPoP proof with nonce - dpopProof, err = keypair.GenerateDPoPProof("POST", metadata.TokenEndpoint, nonce) + dpopProof, err = keypair.GenerateDPoPProof("POST", url, nonce) if err != nil { return nil, err } - retryReq, err := http.NewRequest("POST", metadata.TokenEndpoint, strings.NewReader(data.Encode())) + retryReq, err := http.NewRequest("POST", url, strings.NewReader(data.Encode())) if err != nil { return nil, err } @@ -174,16 +158,14 @@ func ExchangeCodeForTokens(pdsURL, code, verifier, backendURL string, keypair *D return nil, err } defer resp.Body.Close() - } else { - // it's a different 400 error, don't retry - return nil, fmt.Errorf("token exchange failed: 400 - %s", bodyStr) + } else { + return nil, fmt.Errorf("request failed: 400 - %s", bodyStr) } } if resp.StatusCode != 200 { body, _ := io.ReadAll(resp.Body) - fmt.Printf("Token exchange error: %s\n", string(body)) - return nil, fmt.Errorf("token exchange failed: %d - %s", resp.StatusCode, string(body)) + return nil, fmt.Errorf("request failed: %d - %s", resp.StatusCode, string(body)) } var tokens TokenResponse @@ -193,3 +175,35 @@ func ExchangeCodeForTokens(pdsURL, code, verifier, backendURL string, keypair *D return &tokens, nil } + +func ExchangeCodeForTokens(pdsURL, code, verifier, callbackURL string, keypair *DPoPKeyPair) (*TokenResponse, error) { + metadata, err := FetchOAuthMetadata(pdsURL) + if err != nil { + return nil, err + } + + data := url.Values{ + "grant_type": {"authorization_code"}, + "code": {code}, + "redirect_uri": {callbackURL}, + "code_verifier": {verifier}, + "client_id": {callbackURL}, + } + + return postWithDPoP(metadata.TokenEndpoint, data, keypair) +} + +func RefreshAccessToken(pdsURL, refreshToken, callbackURL string, keypair *DPoPKeyPair) (*TokenResponse, error) { + metadata, err := FetchOAuthMetadata(pdsURL) + if err != nil { + return nil, err + } + + data := url.Values{ + "grant_type": {"refresh_token"}, + "refresh_token": {refreshToken}, + "client_id": {callbackURL}, + } + + return postWithDPoP(metadata.TokenEndpoint, data, keypair) +} |
