Skip to content

Authorization #417

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

Open
Savrov opened this issue Nov 22, 2016 · 2 comments
Open

Authorization #417

Savrov opened this issue Nov 22, 2016 · 2 comments

Comments

@Savrov
Copy link

Savrov commented Nov 22, 2016

Hello,
For me it's not clear how to provide basic authorization. Can someone to show me a step-by-step solution, please?
(I've read similar question here, but I didn't get it).
What I want to do:

  • Send username and password to server in Body (via Retrofit)
  • Receive a user object in response
  • If the user doesn't exist, then throw an error.

P.S. Thank you for this great and simple REST server!

@Nilegfx
Copy link
Contributor

Nilegfx commented Nov 28, 2016

Assumptions

Send username and password to server in Body

I am assuming that you mean sending the user and pass encoded (base64) as authentication header, sorry, I am not fimiliar with Retrofit

Receive a user object in response

I am also assuming that you pass back the user only, not both user and pass

Another assumption is you use this for mocking/non-production usage, otherwise, you need to secure it more by validating the user before passing it back in the response

Explanation

In order to achieve the logic you described you may run json-server as a module not from the command line (example provided)

Pseudo Steps

  1. Intercept all json-server incomming requests and check authentecation header existance
  2. do whatever you want to do with the user/pass, in this example we will just decode them and send back the user in response (more accuratly, we will store it in the request and later will send it along with the response "router.render"
  3. Intercept all outgoing responses and inject already-saved-from-step-1 user

I've attached this simple quick repo for you, feel free to clone and use it.

let's get our hands dirty

server.js

var jsonServer = require('json-server')
var server = jsonServer.create()
var router = jsonServer.router('db.json')
var middlewares = jsonServer.defaults()

function simpleAuth(req, res, next) {

  if (req.headers.authorization) {

    // user and password are stored in the authorization header
    // do whatever you want with them
    var user_and_password = new Buffer(req.headers.authorization.split(" ")[1], 'base64').toString();

    // for example, get the username
    var user_only = user_and_password.split(':')[0];


    /*
     *  I am not sure if you want to only send the user as a simple confirmation
     *  or you want to apply your own logic, like, really authenticate/validate
     *  the user against users database, static users .. etc
     *
     *  in production, it is recommended to validate the user by somehow.
     */

    
    // and save it in the request for later use in the `router.render` method
    req.user = user_only;

    // continue doing json-server magic
    next();

  } else {
    // it is not recommended in REST APIs to throw errors,
    // instead, we send 401 response with whatever erros
    // we want to expose to the client
    res.status(401).send({error: 'unauthorized'})
  }
}

// this method overwrites the original json-server's way of response
// with your custom logic, here we will add the user to the response
router.render = function (req, res) {

  // manually wrap any response send by json-server into an object
  // this is something like `res.send()`, but it is cleaner and meaningful
  // as we're sending json object not normal text/response
  res.json({
    user: req.user, // the user we stored previously in `simpleAuth` function
    body: res.locals.data // the original server-json response is stored in `req.locals.data`
  })
}

// start setting up json-server middlewares
server.use(middlewares)

// before proceeding with any request, run `simpleAuth` function
// which should check for basic authentication header .. etc
server.use(simpleAuth);

// continue doing json-server magic
server.use(router);

// start listening to port 3000
server.listen(3000, function () {
  console.log('JSON Server is running on port 3000');
})

db.json

{
  "posts": [
    {
      "id":1,
      "title": "first post title",
      "name": "ahmed ayoub"
    }
  ]
}

running the exampl (clone the provided repo)

git clone https://github.com/Nilegfx/json-server-answer-417.git

cd json-server-answer-417

npm install

node server

running the app (manually)

  • place index.js and db.json in the same directory
  • from within this directory, run
node server

make a request with basic authentication

from your command line, run

curl -u yourusername:yourpassword http://localhost:3000/posts

responses with status 200:

{
  "user": "yourusername",
  "body": [
    {
      "id": 1,
      "title": "first post title",
      "name": "ahmed ayoub"
    }
  ]
}

a request without basic authentication

from your command line, run

curl http://localhost:3000/posts

**responses with status 401:

{
  "error": "unauthorized"
}

Hope it helps.

@Savrov
Copy link
Author

Savrov commented Dec 1, 2016

@Nilegfx very thank you! I need only one hint more.
In want to get a user object that has the same username as in authentecation header.
My db.json is like:

"users": [
    {
      "id": 1,
      "username": "yourusername",
      "password": "yourpassword",
      "firstname": "yourfirstname",
      "lastname": "yourlastname",
      // other fields
    },
    {
      "id": 2,
      "username": "user",
      "password": "user"
      "firstname": "userfirstname",
      "lastname": "userlastname",
      // other fields
    }

So, if i request
curl -u yourusername:yourpassword http://localhost:3000/users
expected answer is:

{
      "id": 1,
      "username": "yourusername",
      // other fields, but w/o password field.
}

How can i achive that kind of "selection"?
Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@Nilegfx @Savrov and others