Role-based access control (RBAC) restricts access to all or some features of an application based on a user's role within the application. For example, only users with an
Adminrole should be able to approve or delete other users; only users with aDevrole should have access to debug logs.We call this part of auth: "Authorization". Authentication is verifying the credentials of a user, Authorization is verifying that the user can access certain features.
- Implement bearer authentication and authorization
- Use role-based authorization to limit API access to specific user groups
- Use enums in Prisma to define two user roles: User and Admin
- Copy the
.env.examplefile and rename your copy to.env - Edit the
DATABASE_URLvariable in.env, swappingYOUR_DATABASE_URLfor the URL of your database - If you have not previously done so (e.g. for a past exercise), create another separate TEST database instance
- Edit the
TEST_DATABASE_URLvariable in.env, swappingYOUR_TEST_DB_URLfor the URL of the separate TEST database instance you just created - Run
npm cito install the project dependencies. - Run
npx prisma migrate resetto execute the existing migrations & data seed. Pressywhen it asks if you're sure.
Run the app with npm start
- Use an enum to define two roles in the prisma schema:
USERandADMIN. Add a role property to the User model, defaulting to the USER role. - Create a migration for your schema changes & regenerate the prisma client. Revisit previous exercises if you need a refresher on the commands needed for this.
- Explore the test/api/routes/user.spec.js and test/api/routes/post.spec.js files to figure out the next steps. The exercise is considered complete when all of the tests pass. You must not change any of the tests.
- Run the tests and try to understand fully what they're asking for
- Try to come up with a plan for which tests you want to pass first and how you might do it. This could be noting down what new routes might be needed, changes that need to be made to existing routes etc.
- This process is equivalent to building an API to an API Spec - this time you're building to a pre-defined set of tests instead
- First, make sure you have created / setup the test database instance and env var, as described in the "Setting Up" section.
- Next, run the command
npm run test:migration- this will run the schema migrations against the test database. You need to do this after making any schema changes. - Run the test suite with
npm testfor core requirements.
Option 1
- Implement a new model named
Permissionwhich connects roles to specific permissions. Example dataset:
| id | role | permission |
|---|---|---|
| 1 | ADMIN | DELETE_ANY_USER |
| 2 | ADMIN | DELETE_ANY_POST |
| 3 | USER | CREATE_POSTS |
| 4 | USER | DELETE_MY_POST |
| 5 | USER | DELETE_MY_USER |
- You'll then need to check that the user performing an action has access to the relevant permission instead of just checking their role. For example, on
DELETE /posts/3you'll check that the authenticated user has access to theDELETE_MY_POSTpermission if that post was created by the authenticated user, or theDELETE_ANY_POSTpermission if not.
This is one approach used for fine-tuning user permissions in an app. You could take this one step further by replacing the role enum with a model and adding a join table to remove the possibility of adding duplicate permission names.
You might need to change the existing tests to satisfy this extension - do so within reason. You should try to create your own new tests as well.
Option 2
- Switch Bearer auth for a different style of auth (e.g. OAuth2, passport.js)
You might need to change the existing tests to satisfy this extension - do so within reason.
Option 3
- Create a front-end application to consume this API. You are free to use any technology for this - the only requirements are:
- registration & login forms
- post creation & post list views
- a page that only admins can access to view a list of users
- (optional extra) admins can delete posts and users
- (optional extra) users can delete their own posts
- (optional extra) user-friendly error messages on the frontend