Giter Club home page Giter Club logo

json-server-auth's Introduction

πŸ” JSON Server Auth

JWT authentication middleware for JSON Server

Because you also need a fake authentication & authorization flow for your prototyping.

Getting started

Install both JSON Server and JSON Server Auth :

# NPM
npm install -D json-server json-server-auth

# Yarn
yarn add -D json-server json-server-auth

Create a db.json file with a users collection :

{
  "users": []
}

Start JSON server (with JSON server Auth as middleware) :

json-server db.json -m ./node_modules/json-server-auth
# with json-server installed globally and json-server-auth installed locally
πŸ“’ but wait !

As a convenience, json-server-auth CLI exposes json-server bundled with its middlewares :

json-server-auth db.json
# with json-server-auth installed globally

It exposes and works the same for all JSON Server flags.

Authentication flow πŸ”‘

JSON Server Auth adds a simple JWT based authentication flow.

Register πŸ‘₯

Any of the following routes registers a new user :

  • POST /register
  • POST /signup
  • POST /users

email and password are required in the request body :

POST /register
{
  "email": "[email protected]",
  "password": "bestPassw0rd"
}

The password is encrypted by bcryptjs.

The response contains the JWT access token (expiration time of 1 hour), and the user data (without the password) :

201 Created
{
  "accessToken": "xxx.xxx.xxx",
  "user": {
    "id": 1,
    "email": "[email protected]"
  }
}
Other properties

Any other property can be added to the request body without being validated :

POST /register
{
  "email": "[email protected]",
  "password": "bestPassw0rd",
  "firstname": "Olivier",
  "lastname": "Monge",
  "age": 32
}
Update

Any update to an existing user (via PATCH or PUT methods) will go through the same process for email and password.

Login πŸ›‚

Any of the following routes logs an existing user in :

  • POST /login
  • POST /signin

email and password are required, of course :

POST /login
{
  "email": "[email protected]",
  "password": "bestPassw0rd"
}

The response contains the JWT access token (expiration time of 1 hour), and the user data (without the password) :

200 OK
{
  "accessToken": "xxx.xxx.xxx",
  "user": {
    "id": 1,
    "email": "[email protected]",
    "firstname": "Olivier",
    "lastname": "Monge"
  }
}

JWT payload πŸ“‡

The access token has the following claims :

  • sub : the user id (as per the JWT specs).
  • email : the user email.

Authorization flow πŸ›‘οΈ

JSON Server Auth provides generic guards as route middlewares.

To handle common use cases, JSON Server Auth draws inspiration from Unix filesystem permissions, especialy the numeric notation.

  • We add 4 for read permission.
  • We add 2 for write permission.

Of course CRUD is not a filesystem, so we don't add 1 for execute permission.

Similarly to Unix, we then have three digits to match each user type :

  • First digit are the permissions for the resource owner.
  • Second digit are the permissions for the logged-in users.
  • Third digit are the permissions for the public users.

For example, 640 means that only the owner can write the resource, logged-in users can read the resource, and public users cannot access the resource at all.

The resource owner πŸ›€

A user is the owner of a resource if that resource has a userId property that matches his id property. Example:

// The owner of
{ id: 8, text: 'blabla', userId: 1 }
// is
{ id: 1, email: '[email protected]' }

Private guarded routes will use the JWT sub claim (which equals the user id) to check if the user actually owns the requested resource, by comparing sub with the userId property.

Except for the actual users collection, where the JWT sub claim must match the id property.

Guarded routes πŸš₯

Guarded routes exist at the root and can restrict access to any resource you put after them :

Route Resource permissions
/664/* User must be logged to write the resource.
Everyone can read the resource.
/660/* User must be logged to write or read the resource.
/644/* User must own the resource to write the resource.
Everyone can read the resource.
/640/* User must own the resource to write the resource.
User must be logged to read the resource.
/600/* User must own the resource to write or read the resource.
/444/* No one can write the resource.
Everyone can read the resource.
/440/* No one can write the resource.
User must be logged to read the resource.
/400/* No one can write the resource.
User must own the resource to read the resource.

Examples

  • Public user (not logged-in) does the following requests :
Request Response
GET /664/posts 200 OK
POST /664/posts
{text: 'blabla'}
401 UNAUTHORIZED
  • Logged-in user with id: 1 does the following requests :
Request Response
GET /600/users/1
Authorization: Bearer xxx.xxx.xxx
200 OK
GET /600/users/23
Authorization: Bearer xxx.xxx.xxx
403 FORBIDDEN

Setup permissions πŸ’‘

Of course, you don't want to directly use guarded routes in your requests. We can take advantage of JSON Server custom routes feature to setup resource permissions ahead.

Create a routes.json file :

{
  "/users*": "/600/users$1",
  "/messages*": "/640/messages$1"
}

Then :

json-server db.json -m ./node_modules/json-server-auth -r routes.json
# with json-server installed globally and json-server-auth installed locally
πŸ“’ but wait !

As a convenience, json-server-auth CLI allows you to define permissions in a more succinct way :

{
  "users": 600,
  "messages": 640
}

Then :

json-server-auth db.json -r routes.json
# with json-server-auth installed globally

You can still add any other normal custom routes :

{
  "users": 600,
  "messages": 640,
  "/posts/:category": "/posts?category=:category"
}

Module usage πŸ”©

If you go the programmatic way and use JSON Server as a module, there is an extra step to properly integrate JSON Server Auth :

⚠️ You must bind the router property db to the created app, like the JSON Server CLI does, and you must apply the middlewares in a specific order.

const jsonServer = require('json-server')
const auth = require('json-server-auth')

const app = jsonServer.create()
const router = jsonServer.router('db.json')

// /!\ Bind the router db to the app
app.db = router.db

// You must apply the auth middleware before the router
app.use(auth)
app.use(router)
app.listen(3000)

Permisssions Rewriter

The custom rewriter is accessible via a subproperty :

const auth = require('json-server-auth')

const rules = auth.rewriter({
  // Permission rules
  users: 600,
  messages: 640,
  // Other rules
  '/posts/:category': '/posts?category=:category',
})

// You must apply the middlewares in the following order
app.use(rules)
app.use(auth)
app.use(router)

TODO πŸ“œ

  • Use JSON Server id and foreignKeySuffix parameters
  • Handle query params in list requests to secure guarded routes more precisely
  • Allow configuration of :
    • Users collection name
    • Minimum password length
    • JWT expiry time
    • JWT property name in response
  • Implement JWT Refresh Token
  • Possibility to disable password encryption ?

json-server-auth's People

Contributors

jeremyben avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-server-auth's Issues

Problems when creating resource with owner-only writing.

Hello. I tried to set up a json-server-auth API. I want a resource to only be modifiable by the owner so I used code 644 in the route. However, when I try to create a new resource of the kind with a logged user, including the token in the header as "'Authorization': 'Bearer xxx.xxx.xxx'" I get a "Forbidden" error. There is no information in the documentation about the creation of resources or how the permissions affect it (since the new element to be introduced has, technically, no userId when it is sent).

PUT method changes user password

What's up!

I'm using Angular 8 with json-server -auth and got a problem with PUT method. Every time I send a PUT request to users collection, it changes user password. It seems to hashing again already hashed password.

I send a request like this:
this.httpClient .put<User>(this.databaseService.databaseURL + '/users/' + this.authService.getCurrentUserID(), JSON.stringify(updatedUserData), this.databaseService.httpOptions) .subscribe(res => console.log(res));

It sends all data correctly but the password.
I assume I've implemented it in the wrong way. Had anyone such a problem?

I've found out that to send a PUT request, the email and password must be sent as well so I can't skip changing them. What might be the best solution for this issue?

Cannot find module express

I followed the instructions in the documentation, but you're saying you can't find the express, and it's already installed too.

Did you have any idea how to proceed?

image

Error: Cannot find module 'json-server-auth/guards'

Bonjour :)

I followed the documentation about the Permissions Rewriter but there seems to be an issue when I am requiring the module:

const { rewriter } = require('json-server-auth/guards');

Here is the whole code for your reference:

const jsonServer = require('json-server');
const auth = require('json-server-auth');
const { rewriter } = require('json-server-auth/guards');

const app = jsonServer.create();
const router = jsonServer.router('db.json');
const port = process.env.PORT || 3000;

// Bind the router db to the app
app.db = router.db;

// Permission rules
const rules = rewriter({
    users: 600,
    clients: 600,
    reports: 600
});

app.use(auth);
app.use(rules);
app.use(router);
app.listen(port);

What am I doing wrong?

404 Not Found

i'm running the JSON Server on glitch.com and i'm using postman to post the data and when i send the request nothing seemed to happen and i got the status 404 Not Found am i missing something or doing something wrong?
image

integrate json-server-auth with express server

const path = require("path");
const express = require("express");
const app = express();
const DIR = "";
const PORT = 3000;
var jsonServer = require("json-server");
const auth = require("json-server-auth");

app.use("/", jsonServer.router("db.json"));
app.use(auth);

app.listen(PORT, () => console.log("server started on " + PORT));

old code without express
const jsonServer = require("json-server");
const auth = require("json-server-auth");

const app = jsonServer.create();
const router = jsonServer.router("db.json");
const middlewares = jsonServer.defaults();
const port = process.env.PORT || 3000;

const cors = require("cors"); // need to install cors

// /!\ Bind the router db to the app
app.db = router.db;
app.use(auth);
app.options("*", cors());

app.use(middlewares);
app.use(router);

app.listen(port);

Permission Error??

I write rewrite rule as below.
(I want to allow just 600 permission for 'users')

==> users: 600

[try 1] - OK
get "my.domain/users

"Missing authorization header"

[try 2] - NOK
get "my.domain/666/users

[
{
"email": "[email protected]",
"password": "$2a$10$Ka37Uw7JptWA2bYH5FzqMe..eWiuS09B9Tul2FN1u0UqRaOfaElyy",
"id": 1
}
]

How to logout?

I've looked through the source code, but only can find a login, register, update and create.

How can I logout?

error: "You must add a "users" collection to your db"

I used to work only with json-server but I need some authentification.
So I followed all the instructions from installing json-server-auth and creating db.json with users collections.
But when using POST /login or POST /users, I get an error.
What am I missing?

This is what I get in the console.
Screenshot from 2020-04-01 17-01-38

npm installation does not work, looking for non existent path

I’m having trouble with installation using npm install -D json-server-auth I have json-server already installed. I get an error: ENOENT: no such file or directory, chmod /Users/{username}/{myapp}/node_modules/json-server-auth/dist\bin.js seems to me that the reference to dist\bin.js might be the problem.

Using mac OS 10.15.3
Node v12.13.1
NPM v6.12.1

I tried removing node_modules, deleting package.lock.json, and then trying to install again, but with no luck. getting the same error.

yarn installation worked with no problem

Problem running on Linux

I'm unable to run json-server-auth from a NPM script

"scripts": {
    "start": "run-p -r start:*",
    "start:cra": "react-scripts start",
    "start:json-server": "json-server-auth -p 3333 db.json",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
},
"proxy": "http://localhost:3333",
$  npm run start:json-server

> [email protected] start:json-server /home/user/projects/xstate-playground
> json-server-auth -p 3333 db.json

/usr/bin/env: Β«node\rΒ»: Not found file or directory
npm ERR! code ELIFECYCLE
npm ERR! syscall spawn
npm ERR! file sh
npm ERR! errno ENOENT
npm ERR! [email protected] start:json-server: `json-server-auth -p 3333 db.json`
npm ERR! spawn ENOENT
npm ERR! 
npm ERR! Failed at the [email protected] start:json-server script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/user/.npm/_logs/2020-02-12T20_04_55_632Z-debug.log

The problem is relates to End of Line (EOL) character, in your case CRLF but in Linux and Mac the EOL is LR

Reproduction repository

https://github.com/leosuncin/xstate-playground

"Email and password are required"

I keep getting a 400 bad response with the message "Email and password are required". I am using Postman with all the info in the screenshot below. Please help.
Screen Shot 2020-04-07 at 12 27 48 PM

CORS Preflight OPTIONS request returns "401 Unauthorized"

Hi!

I am currently facing a problem regarding CORS preflight requests in my application. If I want to fetch user data from a protected JSON server route (600), it says the OPTIONS preflight request is missing an authorization header. Therefore, the GET request is not following afterwards and the fetching fails (although I added the correct Authorization header on the initial GET request).

That seems to be an issue with json-server-auth itself because the W3 specs states that a preflight OPTIONS request should never contain any authorization?

How to get user profile?

I tried different URLs (/profile, /me) for getting user profile by assessToken but didnt find it. Please, help me to find out how to get userInfo (if it exists )??

CLI command cannot find module json-server

I installed json-server and json-server auth, but when I try the CLI command: npx json-server-auth data/db.json --port 8000
I get this error:
Error: Cannot find module 'json-server'
Require stack:

  • D:\sneha\reactjs\projects\codebook\node_modules\json-server-auth\dist\guards.js
  • D:\sneha\reactjs\projects\codebook\node_modules\json-server-auth\dist\bin.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1144:15)
    at Module._load (node:internal/modules/cjs/loader:985:27)
    at Module.require (node:internal/modules/cjs/loader:1235:19)
    at require (node:internal/modules/helpers:176:18)
    at Object. (D:\sneha\reactjs\projects\codebook\node_modules\json-server-auth\dist\guards.js:6:20)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Module.require (node:internal/modules/cjs/loader:1235:19) {
    code: 'MODULE_NOT_FOUND',
    requireStack: [
    'D:\sneha\reactjs\projects\codebook\node_modules\json-server-auth\dist\guards.js',
    'D:\sneha\reactjs\projects\codebook\node_modules\json-server-auth\dist\bin.js'
    ]
    }

Able to get posts that belong to another user

given: "users": [ {"id": 1}, {"id": 2} ], "posts": [ {"id": 1, "text": "hello", "userId": 1}, {"id": 2, "text": "world", "userId": 2}] and
access token: xxx.xxx.xxx for user id:1
when: curl -H "Authorization: Bearer xxx.xxx.xxx" http://localhost:3000/600/posts
expect: only [ { "id": 1, "text": "hello", "userId": 1} ]
actual: [ { "id": 1, "text": "hello", "userId": 1}, {"id": 2, "text": "world", "userId": 2} ]

"Incorrect password"

Hi, 4 hours of trying to login. I would so much like to use json-server-auth. Can you help?

Below I am showing HTTPie, but trials with Postman, wget and cURL have also frustrated me.

CLI:

npm run start

generates:

[email protected] start /Users/oscar/developer/carmen/jsonGUI/json-server-auth-folder
json-server-auth db.json
Loading db.json
Loading /Users/oscar/developer/carmen/jsonGUI/json-server-auth-folder/node_modules/json-server-auth/dist
Done
Resources
http://localhost:3000/users
Home
http://localhost:3000
GET /users 200 6.634 ms - 90

CLI:
http POST localhost:3000/login [email protected] password=bestPassw0rd

generates:.

HTTP/1.1 400 Bad Request
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 20
Content-Type: application/json; charset=utf-8
Date: Sun, 11 Oct 2020 17:18:18 GMT
ETag: W/"14-iEk1d6UpQuw3XSfG5Pju721C6OA"
Expires: -1
Keep-Alive: timeout=5
Pragma: no-cache
Vary: Origin, Accept-Encoding
X-Content-Type-Options: nosniff
X-Powered-By: Express

"Incorrect password"

CLI:
http localhost:3000/users

generates:

[
{
"email": "[email protected]",
"id": "1",
"password": "bestPassw0rd"
}
]

Looking forward to hear from you.
Many thanks,
Oscar

Password Reset ?

Hi ? Can we reset password ? or how to do that manually to end up having hashed version of the password ?

Found 2 errors.

When I build on linux I get these errors any ideas?

$git clone https://github.com/jeremyben/json-server-auth.git
$cd json-server-auth/

$ rimraf dist && tsc -p tsconfig.build.json
src/bin.ts:62:4 - error TS2352: Conversion of type 'undefined' to type 'string[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

62 ;(<string[]>argv.middlewares) = [__dirname]
~~~~~~~~~~~~~~~~~~~~~~~~~~

src/bin.ts:69:39 - error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'string | number | Buffer | URL'.
Type 'unknown' is not assignable to type 'URL'.

69 let routes = JSON.parse(readFileSync(argv.routes, 'utf8'))
~~~~~~~~~~~

Found 2 errors.

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

This is my configuration.
$ tsc --version
Version 3.4.5
$ node --version
v8.12.0
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.6 LTS
Release: 16.04
Codename: xenial

Cli command cannot find module 'express'

Cli command can't find express. Perhaps this should be added to the docs to also install express globally when using the global cli command json-server-auth.

> npx json-server-auth db.json

node:internal/modules/cjs/loader:927
  throw err;
  ^

Error: Cannot find module 'express'
Require stack:
- /usr/local/lib/node_modules/json-server-auth/dist/guards.js
- /usr/local/lib/node_modules/json-server-auth/dist/bin.js

How to get list of items that belongs to logged user ?

Problem

I have a logged in user with id of 2. I would like to get only items from the array that belongs to this user (have userId: 2). How to do that cus every time I make a request im getting in response whole array. Calling request for only one item works just fine - user with id 2 is not authorized to get object with userId: 1
Screen Shot 2023-01-22 at 20 52 31 PM

routes.json

Screen Shot 2023-01-22 at 20 57 31 PM

non user's entities returned on listing entpoints

Hello,

When I call a listing route (ex : GET /characters), all entities are returned, not just user's entities.

Versions :

  • json-server : 0.16.1
  • json-server-auth : 2.0.0

route.json fie:
{ "/users*": "/640/users$1", "/characters*": "/600/characters$1" }

db.json file :
{ "users": [ { "id": 1, "email": "[email protected]", "password: "..." }, { "id": 2, "email": "[email protected]", "password: "..." } ], "characters": [ { "id": 1, "name": "char1", "userId: 1 }, { "id": 2, "name": "char2", "userId: 2 } ] }

Is not working with codes : 600, 640

Thanks

Permissions not working

400, 440, 444 - not working for users if user has login he can add a new user it's bug. Please find mistake and solve it. Thanks for library.

Mouting json-server on non root path breaks DELETE

First off, thank you so much for this module. Really makes it fast to prototype JWT-auth.

It seems that if you mount your json-server-api on a non root path f.e "/api" like this

const rules = rewriter({
  "/api/users*": "/600/api/users$1",
  "/api/myresource*": "/640/api/myresource$1",
})
app.db = router.db
app.use(rules);

app.use(auth)
app.use("/api", router)

resourceId extraction breaks in guards.ts

      const [, mod, resource, id] = path.split('/');

which causes db.get to return undefined and entity.userId to throw an error

            if (id) {
                // prettier-ignore
                const entity = db.get(resource).getById(id).value();
                // get id if we are in the users collection
                const userId = resource === 'users' ? entity.id : entity.userId;
                hasRightUserId = userId == req.claims.sub;
            }

How to configure JWT expiration time?

Hi,

Is it possible to set JWT token expiration time?
Currently it expire after 1 hour, it is too short for comfortable work with api.
Please, add configuration to change this.

Thanks

Conflicts between users and guard methods

First of all : thanks a lot for this tool. It's a great starting point in my quest for simple API setups in development or even small personal production projects. It's well written and as a node/express noob it has been a good learning source too !

Obviously one needs to apply guard to "users" resource but as soon as rights are set users middle wares are not applied anymore (no validation for email/password...).

Example (module usage) :

import jsonServer from 'json-server';
import jsonServerAuth from 'json-server-auth';

const app = jsonServer.create();
const apiRouter = jsonServer.router('db.json');

const rules = jsonServerAuth.rewriter({
    users: 600,
});

app.use('/api', rules);
app.use('/api', jsonServerAuth);
app.use('/api', apiRouter);

// Start
app.listen(4201, '127.0.0.1', function () {
    console.log("Server now listening on 4201");
});

If I then with Postman

POST /api/users

with valid jwt token and empty body it creates a new user with no email and no password.

I guess it's because of the re-writer but I'm not sure how to fix this correctly. Maybe by renaming users routes or resources to avoid conflicts between the two ?

Error 400 Bad Request Question

Hello json-server-auth team,

Context:
Receive 400 error so I can understand I send a bad request. However seems everything fine in my side. So please tell me if I miss something.

My log track the following output:
POST /login 400 1.362 ms - 20

Code:
Request API url :

`
const authEndpoint = "http://localhost:3000/login"

fetch(authEndpoint, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',

  },
  body: JSON.stringify({
    email: this.state.email,
    password: this.state.password,
  }),
}).then((response) => {
  console.log(response.status)
  response.status})
  .catch((error) => {
    console.error(error);
 });`

My db.json config file:

`
{
"signal": [
{ "id": 1, "category": "Fuite d'eau", "user": "[email protected]", "description": "Fuite d'eau issuen de l'Γ©tage 2" }
],

"login":[
    {"email": "[email protected]", "name": "David", "lastname": "M", "password":"test"},
    {"email": "[email protected]", "name": "David", "lastname": "M", "password":"weloveyou"},
    {"email": "remi@test",  "name": "Remi", "lastname": "P", "password":"weloveyou"},
    {"email": "thomas@test",  "name": "Thomas", "lastname": "S", "password":"weloveyou"}


]

}
`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.