diff --git a/lib/Error.js b/lib/Error.js index 3be4c3c734..831aaa6eca 100644 --- a/lib/Error.js +++ b/lib/Error.js @@ -59,6 +59,8 @@ StripeError.generate = function(rawStripeError) { return new _Error.StripeAPIError(rawStripeError); case 'idempotency_error': return new _Error.StripeIdempotencyError(rawStripeError); + case 'invalid_grant': + return new _Error.StripeInvalidGrantError(rawStripeError); } return new _Error('Generic', 'Unknown Error'); }; @@ -73,3 +75,4 @@ _Error.StripeRateLimitError = StripeError.extend({type: 'StripeRateLimitError'}) _Error.StripeConnectionError = StripeError.extend({type: 'StripeConnectionError'}); _Error.StripeSignatureVerificationError = StripeError.extend({type: 'StripeSignatureVerificationError'}); _Error.StripeIdempotencyError = StripeError.extend({type: 'StripeIdempotencyError'}); +_Error.StripeInvalidGrantError = StripeError.extend({type: 'StripeInvalidGrantError'}); diff --git a/lib/StripeResource.js b/lib/StripeResource.js index f374539841..bea29419ea 100644 --- a/lib/StripeResource.js +++ b/lib/StripeResource.js @@ -152,6 +152,15 @@ StripeResource.prototype = { if (response.error) { var err; + // Convert OAuth error responses into a standard format + // so that the rest of the error logic can be shared + if (typeof response.error === 'string') { + response.error = { + type: response.error, + message: response.error_description + } + } + response.error.headers = headers; response.error.statusCode = res.statusCode; response.error.requestId = res.requestId; diff --git a/test/StripeResource.spec.js b/test/StripeResource.spec.js index ccfca3becf..7b19d898a5 100644 --- a/test/StripeResource.spec.js +++ b/test/StripeResource.spec.js @@ -230,6 +230,22 @@ describe('StripeResource', function() { }); }); + it('should handle OAuth errors gracefully', function (done) { + nock('https://connect.stripe.com') + .post('/oauth/token') + .reply(400, { + error: 'invalid_grant', + error_description: 'This authorization code has already been used. All tokens issued with this code have been revoked.' + }); + + realStripe.setMaxNetworkRetries(1); + + realStripe.oauth.token(options.data, function (err) { + expect(err.type).to.equal('StripeInvalidGrantError'); + done(); + }); + }); + it('should retry on a 503 error when the method is POST', function(done) { nock('https://' + options.host) .post(options.path, options.params)