Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Non-401 Error Codes from the validateFunc #245

Open
Oliver-Akins opened this issue May 9, 2022 · 2 comments
Open

Support for Non-401 Error Codes from the validateFunc #245

Oliver-Akins opened this issue May 9, 2022 · 2 comments
Labels
feature New functionality or improvement

Comments

@Oliver-Akins
Copy link

Oliver-Akins commented May 9, 2022

Support plan

  • is this issue currently blocking your project? (yes/no): No
  • is this issue affecting a production system? (yes/no): No

Context

  • node version: v14.17.0
  • module version: 11.0.2
  • environment (e.g. node, browser, native): Node
  • used with (e.g. hapi application, another framework, standalone, ...): Hapi application (Hapi version = 20.2.1)
  • any other relevant information:

What problem are you trying to solve?

I have a system that involves multiple different "regions" of authorization, I want a cookie to only be valid for one of these "regions", and I have added validation checks into the validateFunc. I would love be able to respond to the client with a 403 Forbidden when the cookie provided is for a different "region" than that which it is trying to access.

Example:
I have "regions" 1 and 2, and an authorization cookie is used for region 1, but the user is making a request to GET /region/2 I would like to be able to throw boom.forbidden(), and it set the response code to 403 instead of the plugin only throwing 401 to the user.

Do you have a new or modified API suggestion to solve the problem?

I think a solution following a similar vein as to how @hapi/basic does it where if the validateFunc throws an error(/Boom error) it replaces the default boom.unauthorized()

From the @hapi/basic API documentation for the validate function:

  • Throwing an error from this function will replace default Boom.unauthorized error
@Oliver-Akins Oliver-Akins added the feature New functionality or improvement label May 9, 2022
@Oliver-Akins Oliver-Akins changed the title Support for Non-401 Error Codes in validateFunc Support for Non-401 Error Codes from the validateFunc May 9, 2022
@devinivy
Copy link
Member

devinivy commented May 9, 2022

In the code and tests, the module is fairly explicit about what it's trying to do when it sees a non-unauthorized error:

cookie/test/index.js

Lines 374 to 414 in fa728d7

it('errors in validation function', async () => {
const server = Hapi.server();
await server.register(require('../'));
server.auth.strategy('default', 'cookie', {
cookie: {
password: 'password-should-be-32-characters',
clearInvalid: true,
ttl: 60 * 1000,
name: 'special'
},
validateFunc: function (request, session) {
throw new Error('boom');
}
});
server.auth.default('default');
Helpers.loginWithResourceEndpoint(server);
const res = await server.inject('/login/steve');
expect(res.result).to.equal('steve');
const header = res.headers['set-cookie'];
expect(header.length).to.equal(1);
expect(header[0]).to.contain('Max-Age=60');
const cookie = header[0].match(internals.cookieRx);
let error;
server.ext('onPreResponse', (request, h) => {
error = request.response.data;
return h.continue;
});
const res2 = await server.inject({ method: 'GET', url: '/resource', headers: { cookie: 'special=' + cookie[1] } });
expect(res2.statusCode).to.equal(401);
expect(error).to.be.an.error('boom');
});

That means that we'd need to treat this as a breaking change, most likely.

Since the original error is preserved on the error's data property, you do have an option to get this behavior using a request extension. Something like this should do the trick https://runkit.com/devinivy/627987b9369f5200089451e0:

server.ext({
    type: 'onPreResponse',
    method: (request, h) => {
        const error = request.response;
        if (Boom.isBoom(error) && error.output.statusCode === 401 && error.data instanceof Error) {
            // Preserve original error from Boom.unauthorized()
            return error.data;
        }
        return h.continue;
    }
});

@Oliver-Akins
Copy link
Author

Okay, that makes sense, I can definitely see this being suited as a breaking change since it does change a substantial amount of the existing behaviour.

Thanks for the snippet! It seems like a suitable stand-in for how I'm wanting the erroring to behave.

I think this could be a nice thing to include in a future major-version release, but I am also satisfied with this resolution if this isn't something that is desired within the API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New functionality or improvement
Projects
None yet
Development

No branches or pull requests

2 participants