next-firebase-auth icon indicating copy to clipboard operation
next-firebase-auth copied to clipboard

Extend existing Authentication methods to provide Authorization features

Open gavinharris-dev opened this issue 4 years ago • 5 comments

Is your feature request related to a problem? Please describe. Currently the authorization methods withAuthUserTokenSSR and withAuthUserSSR allow us to validate if a request for page is Authenticated or not. We require that users are not only Authenticated but that the user also has the Custom Claim admin.

Describe the solution you'd like and how you'd implement it The existing withAuthUserTokenSSR and withAuthUserSSR methods will be extended to take 2 optional additional parameters; which will be used to verify if the Authenticated users is Authorized to access the page; and if not redirect them to an appropriate access denied page (provided by the developer).

  • whenAuthed?: AuthAction.RENDER | AuthAction.REDIRECT_TO_APP
  • whenUnauthed?: AuthAction.RENDER | AuthAction.REDIRECT_TO_LOGIN
  • appPageURL?: PageURL
  • authPageURL?: PageURL
  • validator? (user: AuthUser) => boolean
  • accessDeniedPageURL?: PageUrl

The existing method will be extended to accept the 2 emboldened new parameters (validator and accessDeniedPageURL). The method will then, once we have verified the authUser with existing code, run the validator function (if it is provided). If the validator function returns false we should then redirect the users to the accessDeniedPageURL.

Is this a breaking change? No, the additional options would be optional and so an opt in approach to upgrading the interface.

Describe alternatives you've considered The alternative we are currentyl using is handling this in our own code. While this is okay, it would be (I think) a feature that would be nice to push up to the framework.

gavinharris-dev avatar Aug 16 '21 23:08 gavinharris-dev

Auth0's Next.js API could provide some guidance: https://github.com/auth0/nextjs-auth0#api-reference

kmjennison avatar Aug 27 '21 14:08 kmjennison

So Auth0 seems to handle (with their Page Wrapper) Authentication (the binary determination of has this request supplied some valid credentials), but they do not supply a means of Authorization (i.e., do these credentials that the request has supplied grant you access to this page) - They leave it up to the Developer (which is fair I guess) - https://github.com/auth0/nextjs-auth0/issues/321

gavinharris-dev avatar Aug 27 '21 22:08 gavinharris-dev

I also would like to have this feature, for instance to only grant access to a page if the emailVerified key on the User object is true.

lazlothemonkey avatar Aug 29 '21 17:08 lazlothemonkey

So Auth0 seems to handle (with their Page Wrapper) Authentication (the binary determination of has this request supplied some valid credentials), but they do not supply a means of Authorization (i.e., do these credentials that the request has supplied grant you access to this page) - They leave it up to the Developer (which is fair I guess) - auth0/nextjs-auth0#321

Could you share how you would implement this in your code with the package as it currently is?

I've tried using using a custom ´tokenChangedHandler´ which checks ´authUser.emailVerified´, but I am having trouble figuring out how to redirect the user:

const tokenChangedHandler = async (authUser) => {
  const loginAPIEndpoint = "/api/login";
  const logoutAPIEndpoint = "/api/logout";

  let response;
  // If the user is authed, call login to set a cookie.
  if (authUser.id) {
    console.log("authuser", authUser);

    if (!authUser.emailVerified) {
      // how to redirect user to "verify-email" page?
      //this creates an infinite refresh loop:
      window.location.replace("/verify-email");
      //also I cannot use next/router here, as it is not top level of function component
    }

    const userToken = await authUser.getIdToken();
    response = await fetch(loginAPIEndpoint, {
      method: "POST",
      headers: {
        Authorization: userToken,
      },
      credentials: "include",
    });
    console.log(response);

    if (!response.ok) {
      //
      const responseJSON = await response.json();
      throw new Error(
        `Received ${
          response.status
        } response from login API endpoint: ${JSON.stringify(responseJSON)}`
      );
    }
  } else {
    // If the user is not authed, call logout to unset the cookie.
    response = await fetch(logoutAPIEndpoint, {
      method: "POST",
      credentials: "include",
    });
    if (!response.ok) {
      const responseJSON = await response.json();
      throw new Error(
        `Received ${
          response.status
        } response from logout API endpoint: ${JSON.stringify(responseJSON)}`
      );
    }
  }
  return response;
};

lazlothemonkey avatar Sep 04 '21 05:09 lazlothemonkey

@lazlothemonkey - I have not tested this but I was thinking that something like this GIST would work: https://gist.github.com/gavinharris-dev/7ef07eae561e34c05869c21eba6c717e

So what you do is use the withAuthUserSSR getServerSideProps handler, and then wrap the response in your Email Verified Guard. This can then be used to redirect your users (Server Side Redirect with a HTTP 302 and Location Header.

Let me know how this goes! It would be cool to integrate this directly into the withAuthUserSSR as a couple of additional parameters. May need to think about how one could chain the authorization guards though; you may want one guard that ensures that the user is an Admin (with a custom claim) and then another that ensures that the user has a verified email address...

gavinharris-dev avatar Sep 04 '21 23:09 gavinharris-dev

Closing this as something we won't support. It's outside of the current scope of this package, and contributors won't likely have time to build it out and maintain it.

kmjennison avatar Dec 31 '23 20:12 kmjennison