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

feat: Introduce forbidden() #63302

Closed

Conversation

panteliselef
Copy link

@panteliselef panteliselef commented Mar 14, 2024

What?

Similar to the notFound() function and the notFound.js file, this PR follows the convention and introduces the forbidden() function along side the forbiddden.js file.

Why?

While the available notFound and redirect functions can get you a long way, there is only so much you can do with them.

Developers need a way to handle the authorization state of a user across the multiple "contexts" next has, by that I am referring to components, api routes, and server actions. For this case the 403 Forbidden status code can be used.

(We would like to support 401 errors as well)

How?

As a guide, I used the existing implementation of notFound and redirect.

  • Handle 403 errors in components, api routes, server actions, and parallel routes.
  • Handle missing forbidden files. In this case we display a default one.
  • ForbiddenErrorBoundary and Forbidden have been introduced in order to catch and display the 403 error.

To verify that the changes are working the PR includes a minimal set of e2e tests.

How to use ?

Protect a page from a user who does not have the privilege to access it.

// app/team/subscription/page.tsx
import { forbidden } from "next/navigation";

export default function Page(){
  const user = auth() // grap user from headers()

  if(!user.isAdmin) {
    forbidden()
  }

  return <></>;
}

// app/team/subscription/forbidden.tsx
export default function Forbidden(){
  return (
    <>
      <p>Not an admin</p>
     <>
  );
}

Protect an API route from a user who does not have the privilege to access it.

import { forbidden } from "next/navigation";

export const GET = () => {
  const user = auth() // grap user from headers()

  if(!user.isAdmin) {
    forbidden() // -> Returns a 403 response with empty body
  }
  
  return new Response(JSON.strigify({ hasAccess: true }), {statusCode: 200})
};

What's next

  • More e2e tests have been written but not pushed in order to make the review easier.
  • A follow up PR will be opened to handle the 401 Unauthorized status in a similar way.
  • I've added a few comments with questions. I kindly ask the reviewers to take a look at those as they might be important for implementing the feature correctly.

### What?
Similar to the notFound() function and the `notFound.js` file, this PR follows the convention and introduces the `forbidden()` function along side the `forbiddden.js` file.

### Why?
While the available `notFound` and `redirect` functions can get you a long way, there is only so much you can do with them.

Developers need a way to handle the authorized state of a user across the multiple "contexts" next has, by that I am referring to components, api routes, and server actions.
@paqstd-dev
Copy link

Very interesting suggestion. Indeed, it would be convenient to have such functionality. I'll wait for this to be accepted.

@ludwighogstrom
Copy link

ludwighogstrom commented Apr 13, 2024

Nice!

But would it be possible to have a function that could set various response status codes?

Having one function for each code feels a bit verbose in the long run.

@panteliselef
Copy link
Author

The nextjs team will take over this one
#65993 (comment)

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants