jaredhanson / passport-facebook

Facebook authentication strategy for Passport and Node.js.
https://www.passportjs.org/packages/passport-facebook/?utm_source=github&utm_medium=referral&utm_campaign=passport-facebook&utm_content=about
MIT License
1.29k stars 446 forks source link

Allow developers to override state parameter with additional data #265

Closed vanstinator closed 3 years ago

vanstinator commented 4 years ago

Facebook requires that Facebook Login apps use strict redirect validation. For those that need dynamic metadata on a request the recommended solution given by Facebook is to include that data in the state parameter along with the CSRF token. In Passport the OAuth strategy appears to transparently handle the state parameter itself for CSRF purposes (https://github.com/jaredhanson/passport-facebook/issues/14#issuecomment-22733478). While this is great for an out-of-the-box experience it would be helpful if it were possible to override the behavior and provide custom data.

Expected behavior

state can contain arbitrary data given by the implementation

Actual behavior

providing arbitrary data to state causes errors with CSRF

lukeberry99 commented 4 years ago

Any movement on this?

peter-flairbox commented 4 years ago

Work around for now - get the server to set a cookie before going to facebook, that way you'll receive the same cookie on the callback.

hillct commented 3 years ago

It would certainly be a welcome enhancement, to be able to make more robust use of the state parameter (passing encoded JSon objects, etc) but I guess I can make do with the workaround in the short term.

olso commented 3 years ago

If anyone is still interested

simple koa + typescript example

type FacebookState = {
    redirectUrl: string;
  };

  router.get(routes.facebook.init, (ctx, next) => {
    const state: FacebookState = {
      redirectUrl: ctx.headers.referer,
    };

    return passport.authenticate("facebook", {
      ...(state.redirectUrl ? { state: encodeURI(JSON.stringify(state)) } : {}),
      scope: "email",
    })(ctx, next);
  });

  router.get(routes.facebook.callback, (ctx, next) => {
    const { query } = ctx.request;
    const state: FacebookState | null =
      typeof query.state === "string" ? JSON.parse(decodeURI(query.state)) : null;

    return passport.authenticate("facebook", {
      failureRedirect: "/fb-error",
      successRedirect: state ? state.redirectUrl : "/",
    })(ctx, next);
  });
jaredhanson commented 3 years ago

Support for custom, application-level state is now available in passport-oauth2@1.6.0. Details about how to utilize this functionality are available on the blog: Application State in OAuth 2.0