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

It's not possible to have a custom payload on failed authentication #96

Open
sazzer opened this issue May 13, 2015 · 4 comments
Open

It's not possible to have a custom payload on failed authentication #96

sazzer opened this issue May 13, 2015 · 4 comments

Comments

@sazzer
Copy link

sazzer commented May 13, 2015

In some situations it would be very useful to have a custom payload returned when authentication fails. However, it seems that this isn't possible to achieve.

The obvious way of doing this based on the current documentation would be something like:

    percolator.route('/api/authentication/internal', {
        basicAuthenticate: function (username, password, req, res, cb) {
            if (username === 'username' && password === 'password') {
                cb(null, {username: username, password: password});
            } else {
                res.object({'hello': 'world'}).send();
                cb(true);
            }
        }, 
        POST : function (req, res) {
            res.object({auth: req.authenticated}).send();
        }
    });

However, if the basicAuthenticate function does a res.object().send() then you get an "Error: Can't set headers after they are sent" logged, and whilst the custom object is sent, the HTTP Status code is still set to 200. If the basicAuthenticate does a res.object() but doesn't do a send() then the custom object is never sent.

@sazzer
Copy link
Author

sazzer commented May 13, 2015

It seems that a cleaner way of making this work would be to use the first parameter to the callback to specify a custom payload that can be sent. Either by specifically passing an object to the callback and having it do a 401 and sending that object, or else by supporting some mechanism by which the first parameter contains the status and payload to use.

Alternatively, it would seem that if some object data has been sent to the response object in the authentication callback then it should be honoured and sent down as part of the payload in the event that the callback is called with true as a parameter.

@cainus
Copy link
Owner

cainus commented May 13, 2015

Actually, you've got the solution for getting custom payloads working... just don't call cb(true); after. That callback is the default handler, so if you provide your own handling, you don't need it.

@sazzer
Copy link
Author

sazzer commented May 13, 2015

I can't work out how to actually send a custom payload on an unauthenticated status either though. If I do

res.status.unauthenticated({'hello': 'world'});

then the output is not simply the object

{
    "hello": "world"
} 

but instead you get

{
  "error": {
    "type": 401,
    "message": "Unauthenticated",
    "detail": {
      "hello": "world"
    }
  }
}

That's not useful if you need to change the top level object whilst at the same time using a different status code - such as if I want to implement some other API specification (e.g. OAuth2)

I can see that I can do it manually by setting headers and so on, and that works, but it seems to be a bit of a hole.

@cainus
Copy link
Owner

cainus commented May 13, 2015

The purpose of that res.status interface is for when you're happy with the defaults. If you want to do something else, plain node is still pretty simple:

res.statusCode = 401;
res.object({'hello': 'world'}).send();  

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

No branches or pull requests

2 participants