Skip to content

Commit

Permalink
Add deauthorization for disconnecting accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
cjavilla-stripe committed Jun 25, 2019
1 parent e75eb8e commit b396ce7
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 24 deletions.
45 changes: 42 additions & 3 deletions oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,28 @@ const (
OAuthStripeUserGenderMale OAuthStripeUserGender = "male"
)

// Type of Errors raised when failing authorization.
type OAuthError string

// List of supported OAuthError values.
const (
OAuthErrorInvalidGrant OAuthError = "invalid_grant"
OAuthErrorInvalidRequest OAuthError = "invalid_request"
OAuthErrorInvalidScope OAuthError = "invalid_scope"
OAuthErrorUnsupportedGrantType OAuthError = "unsupported_grant_type"
OAuthErrorUnsupportedResponseType OAuthError = "unsupported_response_type"
)


// Type of Errors raised when failing authorization.
type DeauthorizationError string

// List of supported DeauthorizationError values.
const (
DeauthorizationErrorInvalidClient DeauthorizationError = "invalid_client"
DeauthorizationErrorInvalidRequest DeauthorizationError = "invalid_request"
)

// Params for the stripe_user OAuth Authorize params.
type OAuthStripeUserParams struct {
BlockKana *string `form:"block_kana"`
Expand All @@ -51,9 +73,9 @@ type OAuthStripeUserParams struct {
City *string `form:"city"`
Country *string `form:"country"`
Currency *string `form:"currency"`
DobDay *int `form:"dob_tay"`
DobMonth *int `form:"dob_month"`
DobYear *int `form:"dob_year"`
DobDay uint64 `form:"dob_day"`
DobMonth uint64 `form:"dob_month"`
DobYear uint64 `form:"dob_year"`
Email *string `form:"email"`
FirstName *string `form:"first_name"`
FirstNameKana *string `form:"first_name_kana"`
Expand Down Expand Up @@ -85,6 +107,13 @@ type AuthorizeURLParams struct {
StripeUser *OAuthStripeUserParams `form:"stripe_user"`
}

// Params for deauthorizing an account.
type DeauthorizeParams struct {
Params `form:"*"`
ClientID *string `form:"client_id"`
StripeUserID *string `form:"stripe_user_id"`
}

// OAuthTokenParams is the set of paramaters that can be used to request
// OAuthTokens.
type OAuthTokenParams struct {
Expand All @@ -100,10 +129,20 @@ type OAuthTokenParams struct {
// https://stripe.com/docs/connect/oauth-reference#post-token
type OAuthToken struct {
AccessToken string `json:"access_token"`
Error OAuthError `json:"error"`
ErrorDescription string `json:"error_description"`
Livemode bool `json:"livemode"`
RefreshToken string `json:"refresh_token"`
Scope OAuthScopeType `json:"scope"`
StripePublishableKey string `json:"stripe_publishable_key"`
StripeUserID string `json:"stripe_user_id"`
TokenType OAuthTokenType `json:"token_type"`
}

// Deauthorization is the value of the return from deauthorizing.
// https://stripe.com/docs/connect/oauth-reference#post-deauthorize
type Deauthorization struct {
Error DeauthorizationError `json:"error"`
ErrorDescription string `json:"error_description"`
StripeUserID string `json:"stripe_user_id"`
}
16 changes: 16 additions & 0 deletions oauth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,22 @@ func (c Client) New(params *stripe.OAuthTokenParams) (*stripe.OAuthToken, error)
return oauth_token, err
}

func Del(params *stripe.DeauthorizeParams) (*stripe.Deauthorization, error) {
return getC().Del(params)
}

func (c Client) Del(params *stripe.DeauthorizeParams) (*stripe.Deauthorization, error) {
deauthorization := &stripe.Deauthorization{}
err := c.B.Call(
http.MethodPost,
"/oauth/deauthorize",
c.Key,
params,
deauthorization,
)
return deauthorization, err
}

func getC() Client {
return Client{stripe.GetBackend(stripe.ConnectBackend), stripe.Key}
}
104 changes: 83 additions & 21 deletions oauth/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package oauth

import (
"bytes"
"io/ioutil"
// "os"
"io/ioutil"
"net/http"
"testing"
assert "github.com/stretchr/testify/require"
Expand Down Expand Up @@ -46,18 +45,35 @@ func TestAuthorizeURLWithOptionalArgs(t *testing.T) {
func TestAuthorizeURLWithStripeUser(t *testing.T) {
stripe.ClientID = "ca_123"
url := AuthorizeURL(&stripe.AuthorizeURLParams{
ResponseType: stripe.String("test-code"),
StripeUser: &stripe.OAuthStripeUserParams{
BlockKana: stripe.String("block-kana"),
BlockKanji: stripe.String("block-kanji"),
BuildingKana: stripe.String("building-kana"),
BuildingKanji: stripe.String("building-kanji"),
BusinessName: stripe.String("b-name"),
BusinessType: stripe.OAuthStripeUserBusinessTypeLLC,
City: stripe.String("Elko"),
Country: stripe.String("US"),
State: stripe.String("NV"),
Zip: stripe.String("12345"),
ResponseType: stripe.String("test-code"),
StripeUser: &stripe.OAuthStripeUserParams{
BlockKana: stripe.String("block-kana"),
BlockKanji: stripe.String("block-kanji"),
BuildingKana: stripe.String("building-kana"),
BuildingKanji: stripe.String("building-kanji"),
BusinessName: stripe.String("b-name"),
BusinessType: stripe.OAuthStripeUserBusinessTypeLLC,
City: stripe.String("Elko"),
Country: stripe.String("US"),
Currency: stripe.String("USD"),
DobDay: 15,
DobMonth: 10,
DobYear: 2019,
Email: stripe.String("[email protected]"),
FirstName: stripe.String("first-name"),
FirstNameKana: stripe.String("first-name-kana"),
FirstNameKanji: stripe.String("first-name-kanji"),
Gender: stripe.OAuthStripeUserGenderFemale,
LastName: stripe.String("last-name"),
LastNameKana: stripe.String("last-name-kana"),
LastNameKanji: stripe.String("last-name-kanji"),
PhoneNumber: stripe.String("999-999-9999"),
PhysicalProduct: stripe.Bool(false),
ProductDescription: stripe.String("product-description"),
State: stripe.String("NV"),
StreetAddress: stripe.String("123 main"),
Url: stripe.String("http://example.com"),
Zip: stripe.String("12345"),
},
})

Expand All @@ -69,22 +85,39 @@ func TestAuthorizeURLWithStripeUser(t *testing.T) {
assert.Contains(t, url, "stripe_user[business_name]=b-name")
assert.Contains(t, url, "stripe_user[business_type]=llc")
assert.Contains(t, url, "stripe_user[city]=Elko")
assert.Contains(t, url, "stripe_user[state]=NV")
assert.Contains(t, url, "stripe_user[country]=US")
assert.Contains(t, url, "stripe_user[street_address]=123 main")
assert.Contains(t, url, "stripe_user[currency]=USD")
assert.Contains(t, url, "stripe_user[dob_day]=15")
assert.Contains(t, url, "stripe_user[dob_month]=10")
assert.Contains(t, url, "stripe_user[dob_year]=2019")
assert.Contains(t, url, "stripe_user[email]=test%40example.com")
assert.Contains(t, url, "stripe_user[first_name]=first-name")
assert.Contains(t, url, "stripe_user[first_name_kana]=first-name-kana")
assert.Contains(t, url, "stripe_user[first_name_kanji]=first-name-kanji")
assert.Contains(t, url, "stripe_user[gender]=female")
assert.Contains(t, url, "stripe_user[last_name]=last-name")
assert.Contains(t, url, "stripe_user[last_name_kana]=last-name-kana")
assert.Contains(t, url, "stripe_user[last_name_kanji]=last-name-kanji")
assert.Contains(t, url, "stripe_user[phone_number]=999-999-9999")
assert.Contains(t, url, "stripe_user[physical_product]=false")
assert.Contains(t, url, "stripe_user[product_description]=product-description")
assert.Contains(t, url, "stripe_user[state]=NV")
assert.Contains(t, url, "stripe_user[street_address]=123+main")
assert.Contains(t, url, "stripe_user[url]=http%3A%2F%2Fexample.com")
assert.Contains(t, url, "stripe_user[zip]=12345")
}


// RoundTripFunc .
// RoundTripFunc.
type RoundTripFunc func(req *http.Request) *http.Response

// RoundTrip .
// RoundTrip.
func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req), nil
}

//NewTestClient returns *http.Client with Transport replaced to avoid making real calls
// NewTestClient returns *http.Client with Transport replaced to avoid making
// real calls
func NewTestClient(fn RoundTripFunc) *http.Client {
return &http.Client{
Transport: RoundTripFunc(fn),
Expand All @@ -104,6 +137,7 @@ func StubConnectBackend(httpClient *http.Client) {

func TestNewOAuthToken(t *testing.T) {
stripe.Key = "sk_123"

// stripe-mock doesn't support connect URL's so this stubs out the server.
httpClient := NewTestClient(func(req *http.Request) *http.Response {
buf := new(bytes.Buffer)
Expand All @@ -126,7 +160,6 @@ func TestNewOAuthToken(t *testing.T) {
}`
return &http.Response{
StatusCode: 200,
// Send response to be tested
Body: ioutil.NopCloser(bytes.NewBufferString(responseBody)),
Header: make(http.Header),
}
Expand Down Expand Up @@ -159,7 +192,6 @@ func TestNewOAuthTokenWithCustomKey(t *testing.T) {

return &http.Response{
StatusCode: 200,
// Send response to be tested
Body: ioutil.NopCloser(bytes.NewBufferString(`{}`)),
Header: make(http.Header),
}
Expand All @@ -172,3 +204,33 @@ func TestNewOAuthTokenWithCustomKey(t *testing.T) {
assert.Nil(t, err)
assert.NotNil(t, token)
}

func TestDeauthorize(t *testing.T) {
stripe.Key = "sk_123"

// stripe-mock doesn't support connect URL's so this stubs out the server.
httpClient := NewTestClient(func(req *http.Request) *http.Response {
buf := new(bytes.Buffer)
buf.ReadFrom(req.Body)
reqBody := buf.String()
assert.Contains(t, req.URL.String(), "https://localhost:12113/oauth/deauthorize")
assert.Contains(t, reqBody, "client_id=sk_999")
assert.Contains(t, reqBody, "stripe_user_id=acct_123")

resBody := `{"stripe_user_id": "acct_123"}`
return &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString(resBody)),
Header: make(http.Header),
}
})
StubConnectBackend(httpClient)

deauthorization, err := Del(&stripe.DeauthorizeParams{
ClientID: stripe.String("sk_999"),
StripeUserID: stripe.String("acct_123"),
})
assert.Nil(t, err)
assert.NotNil(t, deauthorization)
assert.Equal(t, deauthorization.StripeUserID, "acct_123")
}

0 comments on commit b396ce7

Please sign in to comment.