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

Getting 403 forbidden because token has changed #54

Closed
marlonmantilla opened this issue Jul 13, 2015 · 19 comments
Closed

Getting 403 forbidden because token has changed #54

marlonmantilla opened this issue Jul 13, 2015 · 19 comments
Labels
bug
Milestone

Comments

@marlonmantilla
Copy link

@marlonmantilla marlonmantilla commented Jul 13, 2015

Hi guys, I'm working in a HapiJS API and a separate Web client app (Just HTML and JS) which basically will have a form with a CSRF crumb token. So the Web app basically makes a call to GET /generate and HapiJS will return the CSRF token. After that when I submit the form I hit POST /send and sends the token with X-CSRF-Token header but for some reason is returning 403 ...

HAPIJS Routes

server.route([
        {
            method: 'GET',
            path: '/generate',
            handler: Controllers.Auth.generate_csrf,
            config: {
                auth: false,
                jsonp: 'callback'
            }
        },
        // request header "X-CSRF-Token" with crumb value must be set in request for this route
        {
            method: 'POST',
            path: '/send',
            handler: Controllers.Auth.csrf_handshake,
            config: {
                auth: false
            }
        }
    ]);

HapiJS routes handlers:

exports.generate_csrf = function (request, reply) {
    request.log.info(request.info, 'Request to generate CSRF Token');
    return reply({csrf_token: request.plugins.crumb});
};

exports.csrf_handshake = function (request, reply) {
   return reply('OK');
};

On the web side:

(function () {

    var form = $("#sms-form");
    var host = "http://localhost:3002"; // HAPIJS Host

    var getAuth = function () {
        $.ajax({
            url: host + "/generate",
            jsonp: "callback",
            dataType: "jsonp",
            success: function( response ) {
                var token = response.csrf_token; 
                var input = $('<input name="csrf_token" type="hidden" value="'+token+'">');
                form.append(input);
            },
            error: function (req, status, err) {
                console.log('error');
            }
        });
    };

    getAuth();


    form.on('submit', function (e) {
        e.preventDefault();

        var authorizationToken = $(e.currentTarget).find('input[name="csrf_token"]').val();

        console.log(authorizationToken);
        if(authorizationToken) {
            $.ajax({
                type:"POST",
                beforeSend: function (request)
                {
                    request.setRequestHeader("X-CSRF-Token", authorizationToken);
                },
                url: host + "/send",
                data: {crumb: authorizationToken},
                dataType: "json",
                success: function(msg) {
                    console.log(msg);
                }
            });
        }else {
            console.log("We're having issues this request");
        }


    });

})();

Here's plugin config:

{
register: require('crumb'),
options: { restful: false }
}

Also I noticed that when calling multiple times GET /generate is returning the same CSRF token, not sure how to generate a new one per request.

When adding a debugger to crumb/lib/index.js, I noticed that the they're not the same:

          debugger;
            if (content instanceof Stream) {

                return reply(Boom.forbidden());
            }

            if (content[request.route.settings.plugins._crumb.key] !== request.plugins.crumb) {
                return reply(Boom.forbidden());
            }

Am I missing something here ?

@zoe-1

This comment has been minimized.

Copy link

@zoe-1 zoe-1 commented Jul 14, 2015

@marlonmantilla @hapijs/university 's current assignment is related to crumb.
Follow instructions in the README to get started.
Specifics about the assignment are at: Assignment8.
Hopefully, you will join and submit a PR for the current assignment :-) Doing this assignment should clear your questions about crumb.

Plus, I made a sample app fulfilling requirements of Assignment8 here. The app has 100% test coverage and uses crumb in AJAX post requests, so should provide the solutions you are looking for. The tests code for the login and logout routes should be very relevant too. Cheers!

@stongo

This comment has been minimized.

Copy link
Contributor

@stongo stongo commented Jul 14, 2015

If you're trying pass the token as a "X-CSRF-Token" header you'll need to set crumb's plugin option restful: true
Otherwise, crumb expects the token to be in the POST payload: { "crumb": "TOKEN" }

@marlonmantilla

This comment has been minimized.

Copy link
Author

@marlonmantilla marlonmantilla commented Jul 15, 2015

@stongo I tried with both disabling restful: true|false, you can see data: {crumb: authorizationToken} but as soon as I debug the tokens are not the same is like Crumb generate a new one when cheking.

@stongo

This comment has been minimized.

Copy link
Contributor

@stongo stongo commented Oct 22, 2015

Getting a similar error in one test only when converting crumb to hapi 9 f728d64. This may be related to this issue

@stongo stongo added the bug label Oct 22, 2015
@stongo stongo added this to the 5.0.0 milestone Oct 22, 2015
@stongo

This comment has been minimized.

Copy link
Contributor

@stongo stongo commented Nov 12, 2015

Closing due to inactivity. Re-open if this bug still reproduce-able with Crumb >= 5.x

@stongo stongo closed this Nov 12, 2015
@davemackintosh

This comment has been minimized.

Copy link

@davemackintosh davemackintosh commented Nov 19, 2015

@stongo, I'm still seeing this issue with:

Crumb@5.0.0
Hapi@11.1.1
@hoshin

This comment has been minimized.

Copy link

@hoshin hoshin commented Jul 5, 2016

Same here with
Crumb@6.0.2
Hapi@13.4.2

:-/

Note : right now I'm not even trying to integrate the plugin, i'm just fiddling with the "restful.js" demo app (had trouble integrating, so I cut all the "this might be due to some weird plugin interaction / configuration" issues and just tried the demo app barebone.

As far as I can tell, the "generate" function is called on the /crumbed call (when i'd expect to check the token I have in my headers).

I'm using the default configuration. Right now I'm trying to see how it fares when deactivating the auto-generation, so far no luck

@hoanghiep

This comment has been minimized.

Copy link

@hoanghiep hoanghiep commented Jul 5, 2016

Here is my config

server.register({ register: require('crumb'), options :{ restful : true, cookieOptions : {isSecure : false} } }, (err) => {
  Hoek.assert(!err, err);
});

And form

      <form action="/login" method="post">
        <div>{{message}}</div>
        <input type="text" name="username" value="john"/>
        <input type="text" name="password" value="password"/>
        <input type="hidden" name="crumb" value="{{crumb}}"/>
        <input type="submit" value="Đăng nhập">
      </form>

Result
{"statusCode":403,"error":"Forbidden"}

restful : true does not work with form :(

@afgallo

This comment has been minimized.

Copy link

@afgallo afgallo commented Jul 6, 2016

I am also getting the same error as per @hoshin. The generate function gets called twice:

  1. When I request my crumb token via GET /generate
  2. When I post the token to POST /crumbed

Relevant part when debugging:

    // Set crumb cookie and calculate crumb

    if ((settings.autoGenerate ||
        request.route.settings.plugins._crumb) &&
        (request.route.settings.cors ? request.info.cors.isOriginMatch : true)) {

        generate(request, reply);
    }
@hoshin

This comment has been minimized.

Copy link

@hoshin hoshin commented Jul 6, 2016

@stongo I'd gladly re-open if I could but it doesn't seem possible on my end =)

@mtharrison mtharrison reopened this Jul 6, 2016
@genediazjr

This comment has been minimized.

Copy link

@genediazjr genediazjr commented Jul 31, 2016

I encountered this issue as well using the server example.

@stongo stongo modified the milestones: 6.0.3, 5.0.0 Aug 2, 2016
@stongo

This comment has been minimized.

Copy link
Contributor

@stongo stongo commented Aug 2, 2016

found a bug related to the generate function. fixing in upcoming release

@stongo

This comment has been minimized.

Copy link
Contributor

@stongo stongo commented Aug 4, 2016

It might have been a problem with the example, in fact. Using server.plugins.crumb.generate()
If someone can verify #88 that'd be great

@afgallo

This comment has been minimized.

Copy link

@afgallo afgallo commented Aug 5, 2016

@stongo it didn't work for me .... if #88 is only about fixing the example, when I tried to reproduce it on my local env it didn't really work :(
Still keen to help though.

@stongo

This comment has been minimized.

Copy link
Contributor

@stongo stongo commented Aug 5, 2016

@afgallo check the pr example now, forgot to add the generate function args :(
the generate route in the example shouldn't cause the problem you described anymore

@afgallo

This comment has been minimized.

Copy link

@afgallo afgallo commented Aug 6, 2016

@stongo still no luck :(

I noticed that the objects request.plugins.crumb and server.plugins.crumb are different. If this is by design, you can ignore my comment, but wouldn't this cause issues? When calling request.server.plugins.crumb.generate I noticed that request.plugins.crumb was already populated ...

I also created a gist for you to have a look and see if I am making any stupid mistakes: https://gist.github.com/afgallo/e62fba828b2fcb1a96a808f754b94c3f

@afgallo

This comment has been minimized.

Copy link

@afgallo afgallo commented Aug 8, 2016

@stongo finally some good news! I reviewed your tests cases and found what appeared to fix my unit tests.

I simply modified my test cases from:

headers: { 'X-CSRF-token': token }

to:

headers: { 'X-CSRF-token': token, cookie: 'crumb=' + token }

It seems to be working now! I'll let you know if I come across any other issues.

identityclash added a commit to identityclash/hapi-login-test that referenced this issue Aug 9, 2016
@stongo

This comment has been minimized.

Copy link
Contributor

@stongo stongo commented Aug 12, 2016

Excellent @afgallo
For anyone else having issues please use latest example and version 6.0.3 and re-open if there's still an issue.

@stongo stongo closed this Aug 12, 2016
@hoshin

This comment has been minimized.

Copy link

@hoshin hoshin commented Aug 13, 2016

Thanks =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
9 participants
You can’t perform that action at this time.