Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/handlers/authorize-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,11 @@ class AuthorizeHandler {
} catch (err) {
let e = err;

if (!(e instanceof OAuthError)) {
// `InvalidArgumentError` denotes a programming or configuration error and
// its `invalid_argument` code is not a valid OAuth 2.0 error code, so -
// like any non-OAuth error - it is normalised to a `server_error` before
// reaching the client. The original error is retained as `.inner`.
if (!(e instanceof OAuthError) || e instanceof InvalidArgumentError) {
e = new ServerError(e);
}
const redirectUri = this.buildErrorRedirectUri(uri, e);
Expand Down
6 changes: 5 additions & 1 deletion lib/handlers/token-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ class TokenHandler {
} catch (err) {
let e = err;

if (!(e instanceof OAuthError)) {
// `InvalidArgumentError` denotes a programming or configuration error and
// its `invalid_argument` code is not a valid OAuth 2.0 error code, so -
// like any non-OAuth error - it is normalised to a `server_error` before
// reaching the client. The original error is retained as `.inner`.
if (!(e instanceof OAuthError) || e instanceof InvalidArgumentError) {
e = new ServerError(e);
}

Expand Down
49 changes: 49 additions & 0 deletions test/integration/handlers/authorize-handler_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,55 @@ describe('AuthorizeHandler integration', function() {
}
});

it('should redirect with a `server_error` if an `InvalidArgumentError` is thrown while handling the request', async function() {
// A model returning a falsy `authorizationCode` makes `CodeResponseType`
// throw an `InvalidArgumentError`. That is an internal error, not an OAuth
// error, so it must reach the client as a standard `server_error` rather
// than the non-standard `invalid_argument`.
const model = createModel({
getAccessToken: async function() {
return {
user: {},
accessTokenExpiresAt: new Date(new Date().getTime() + 10000)
};
},
getClient: async function() {
return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] };
},
saveAuthorizationCode: async function() {
return { authorizationCode: undefined, client: {} };
}
});
const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model });
const request = new Request({
body: {
client_id: 12345,
response_type: 'code'
},
headers: {
'Authorization': 'Bearer foo'
},
method: {},
query: {
state: 'foobar'
}
});
const response = new Response({ body: {}, headers: {} });

try {
await handler.handle(request, response);
should.fail();
} catch (e) {
e.should.be.an.instanceOf(ServerError);
e.inner.should.be.an.instanceOf(InvalidArgumentError);
e.message.should.equal('Missing parameter: `code`');
const location = new URL(response.get('location'));
location.searchParams.get('error').should.equal('server_error');
location.searchParams.get('error_description').should.equal('Missing parameter: `code`');
location.searchParams.get('state').should.equal('foobar');
}
});

it('should redirect to a successful response with `code` and `state` if successful', async function() {
const client = {
id: 'client-12343434',
Expand Down
38 changes: 38 additions & 0 deletions test/integration/handlers/token-handler_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,44 @@ describe('TokenHandler integration', function() {
});
});

it('should normalise an `InvalidArgumentError` thrown while handling the request to a `server_error`', function() {
// A model that returns malformed token data makes `TokenModel` throw an
// `InvalidArgumentError`. That is an internal error, not an OAuth error, so
// it must reach the client as a standard `server_error` rather than the
// non-standard `invalid_argument`.
const model = Model.from({
getClient: function() { return { grants: ['password'] }; },
getUser: function() { return {}; },
saveToken: function() { return { accessToken: 'foo', client: {}, user: {}, accessTokenExpiresAt: 'not-a-date' }; },
validateScope: function() { return ['baz']; }
});
const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 });
const request = new Request({
body: {
client_id: 12345,
client_secret: 'secret',
username: 'foo',
password: 'bar',
grant_type: 'password',
scope: 'baz'
},
headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' },
method: 'POST',
query: {}
});
const response = new Response({ body: {}, headers: {} });

return handler.handle(request, response)
.then(should.fail)
.catch(function(e) {
e.should.be.an.instanceOf(ServerError);
e.inner.should.be.an.instanceOf(InvalidArgumentError);
e.message.should.equal('Invalid parameter: `accessTokenExpiresAt`');
response.body.should.eql({ error: 'server_error', error_description: 'Invalid parameter: `accessTokenExpiresAt`' });
response.status.should.equal(503);
});
});

it('should return a bearer token if successful', function() {
const token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: ['foobar'], user: {} };
const model = Model.from({
Expand Down
Loading