Skip to content

Commit

Permalink
dnsimple: handle ExchangeAuthorizationForToken error response
Browse files Browse the repository at this point in the history
  • Loading branch information
weppos committed Mar 3, 2016
1 parent 280023b commit ce4241e
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 3 deletions.
41 changes: 38 additions & 3 deletions dnsimple/oauth.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package dnsimple

import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
)
Expand Down Expand Up @@ -32,18 +35,50 @@ type ExchangeAuthorizationRequest struct {
GrantType string `json:"grant_type,omitempty"`
}

// ExchangeAuthorizationError represents a failed request to exchange
// an authorization code for an access token.
type ExchangeAuthorizationError struct {
// HTTP response
HttpResponse *http.Response

ErrorCode string `json:"error"`
ErrorDescription string `json:"error_description"`
}

// Error implements the error interface.
func (r *ExchangeAuthorizationError) Error() string {
return fmt.Sprintf("%v %v: %v %v",
r.HttpResponse.Request.Method, r.HttpResponse.Request.URL,
r.ErrorCode, r.ErrorDescription)
}

// ExchangeAuthorizationForToken exchanges the short-lived authorization code for an access token
// you can use to authenticate your API calls.
func (s *OauthService) ExchangeAuthorizationForToken(authorization *ExchangeAuthorizationRequest) (*AccessToken, error) {
path := versioned("/oauth/access_token")
accessToken := &AccessToken{}

_, err := s.client.post(path, authorization, accessToken)
req, err := s.client.NewRequest("POST", path, authorization)
if err != nil {
return nil, err
}

return accessToken, nil
resp, err := s.client.HttpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

if resp.StatusCode != 200 {
errorResponse := &ExchangeAuthorizationError{}
errorResponse.HttpResponse = resp
json.NewDecoder(resp.Body).Decode(errorResponse)
return nil, errorResponse
}

accessToken := &AccessToken{}
err = json.NewDecoder(resp.Body).Decode(accessToken)

return accessToken, err
}

// AuthorizationOptions represents the option you can use to generate an authorization URL.
Expand Down
26 changes: 26 additions & 0 deletions dnsimple/oauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,32 @@ func TestOauthService_ExchangeAuthorizationForToken(t *testing.T) {
}
}

func TestOauthService_ExchangeAuthorizationForToken_Error(t *testing.T) {
setupMockServer()
defer teardownMockServer()

mux.HandleFunc("/v2/oauth/access_token", func(w http.ResponseWriter, r *http.Request) {
httpResponse := httpResponseFixture(t, "/oauthAccessToken/error-invalid_request.http")

w.WriteHeader(httpResponse.StatusCode)
io.Copy(w, httpResponse.Body)
})

_, err := client.Oauth.ExchangeAuthorizationForToken(&ExchangeAuthorizationRequest{Code: "1234567890", ClientID: "a1b2c3", ClientSecret: "thisisasecret", GrantType: "authorization_code"})
if err == nil {
t.Fatalf("Oauth.ExchangeAuthorizationForToken() expected to return an error")
}

switch v := err.(type) {
case *ExchangeAuthorizationError:
if want := `Invalid "state": value doesn't match the "state" in the authorization request`; v.ErrorDescription != want {
t.Errorf("Oauth.ExchangeAuthorizationForToken() error is %v, want %v", v, want)
}
default:
t.Fatalf("Oauth.ExchangeAuthorizationForToken() error type unknown: %v", v.Error())
}
}

func TestOauthService_AuthorizeURL(t *testing.T) {
clientID := "a1b2c3"
client.BaseURL = "https://api.host.test"
Expand Down
16 changes: 16 additions & 0 deletions fixtures.http/oauthAccessToken/error-invalid_request.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
HTTP/1.1 400 Bad Request
Server: nginx
Date: Mon, 08 Feb 2016 21:24:19 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1454970259
ETag: W/"def417b4ade951f8148bb6a4fa3fcf5a"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: e8c544cf-fcc3-4762-a200-60c0320a2575
X-Runtime: 0.105600
Strict-Transport-Security: max-age=31536000

{"error":"invalid_request","error_description":"Invalid \"state\": value doesn't match the \"state\" in the authorization request"}

0 comments on commit ce4241e

Please sign in to comment.