rockq-org / austack-core

API, Console, Test of austack
32 stars 8 forks source link

As a developer, Dave can use app accessToken to access RESt API #98

Closed hailiang-wang closed 9 years ago

hailiang-wang commented 9 years ago

Description

Get accessToken

https://github.com/arrking/austack-core/issues/97

Solution

Check if accessToken is in request header

Sign user for the request if accessToken is valid

lymanlai commented 9 years ago

data in jwt

sample 1: http://jwt.io/?value=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJSZWlQcjZmT1JZVThUS3owUTBybWFIWkFxc1NtenpyOCIsInNjb3BlcyI6eyJjbGllbnRzIjp7ImFjdGlvbnMiOlsiY3JlYXRlIiwicmVhZCIsImRlbGV0ZSIsInVwZGF0ZSJdfSwiY2xpZW50X2tleXMiOnsiYWN0aW9ucyI6WyJyZWFkIiwidXBkYXRlIl19fSwiaWF0IjoxNDM2MjM4NjM5LCJqdGkiOiI0MTA0ODEzZjBmNDNlNzhlNmEyODgxOGI0NWU4Y2IzOCJ9.lwSGYif6mfjZ53zQ6jaZ_9YbPotDRSTEbX_3Buu3U5E

{
  "aud": "ReiPr6fORYU8TKz0Q0rmaHZAqsSmzzr8",
  "scopes": {
    "clients": {
      "actions": [
        "create",
        "read",
        "delete",
        "update"
      ]
    },
    "client_keys": {
      "actions": [
        "read",
        "update"
      ]
    }
  },
  "iat": 1436238639,
  "jti": "4104813f0f43e78e6a28818b45e8cb38"
}

same 2: http://jwt.io/?value=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJSZWlQcjZmT1JZVThUS3owUTBybWFIWkFxc1NtenpyOCIsInNjb3BlcyI6eyJjbGllbnRzIjp7ImFjdGlvbnMiOlsiY3JlYXRlIl19fSwiaWF0IjoxNDM2MjM4NjEwLCJqdGkiOiIwNTMxOTljZTU1OTU1MDVkN2I4MTk3ZDc2OWQ0ODE1MiJ9.kDcTETreCF00NNw-4s8f6UbzFOTDQE7h3X7PFog3X2w

{
  "aud": "ReiPr6fORYU8TKz0Q0rmaHZAqsSmzzr8",
  "scopes": {
    "clients": {
      "actions": [
        "create"
      ]
    }
  },
  "iat": 1436238610,
  "jti": "053199ce5595505d7b8197d769d48152"
}

we can see they have different scopes data. on auth0 api server, it will check them to see if the scope is correct.

lymanlai commented 9 years ago

client api

Get all clients Create a client Get a client Delete a client Update a client

user api

List or search usersBETA Create a userBETA Delete all users Get a user Delete a user Update a userBETA Link a user account Delete a user's multifactor provider Unlink a user account

lymanlai commented 9 years ago

https://auth0.com/blog/2014/12/02/using-json-web-tokens-as-api-keys/

Granular Security: API Keys provide an all-or-nothing access. JSON Web Tokens can provide much finer grained control. Homogenous Auth Architecture: Today we use cookies, API keys, home grown SSO solutions, OAuth etc. Standardizing on JSON Web Tokens gives you an homogenous token format across the board. Decentralized Issuance: API keys depend on a central storage and a service to issue them. JSON Web Tokens can be "self-issued" or be completely externalized, opening interesting scenarios as we will see below. OAuth2 Compliance: OAuth2 uses an opaque token that relies on a central storage. You can return a stateless JWT instead, with the allowed scopes and expiration. Debuggability: API keys are opaque random strings. JSON Web Tokens can be inspected. Expiration Control: API keys usually don't expire unless you revoke them. JSON Web Tokens can (and often do) have an expiration. Devices: You can't put an API key that has full access on a device, because what is on a phone or tablet can easily be stolen. But you can put a JWT with the right set of permissions.

use http://swagger.io/ to build the https://auth0.com/docs/api/v2 system

For Auth0, we decided to build our own documentation using swagger. Since we are a multi-tenant system, each tenant has an API Key and Secret that is used to sign the token. As a developer, you mark which scopes you need and a token will be auto-generated. You can copy and paste it to jwt.io to see the structure (this is the debuggable piece, by the way).

Conclusion & Resources

We have shown a new way of securing APIs based on JSON Web Tokens. This approach has some interesting benefits, in particular around granular security. In future posts we will go over other aspects, starting with how to revoke tokens.

Below are some of the resources that we used in our node.js backend implementation:

The hapi.js framework to create the API. A fork of hapi-auth-jwt with support for multitenant apps to handle authentication with JWTs. The awesome ratify library to both validate API input using JSON schemas and automatically generate swagger from said schemas for our docs. Swagger's support for arbitrary authorizations objects and a slightly customized swagger-ui template to render the scopes per operation.

lymanlai commented 9 years ago

https://auth0.com/docs/api/v2/changes

API v1 vs v2

v2 uses JWTs instead of opaque tokens. v2 allows you to send id_token to perform operations on the user to which the id_token belongs. v2 has user_metadata for trivial data about users and app_metadata for data that affects how your applications work. Unlike metadata in API v1, those fields are not merged into the root user object. Less endpoints to make development easier since things work as developers would expect and there is less choice with the same features. All endpoints will work with ids, no more strings (such as connection name). New user_id (available as v2id with "usr" prefix) and clientID ("cli_" prefix) formats to easily recognize the type of entity based on its id. Improved input validation and error messages. Only one connection with the same is exposed per tenant, instead of one per client. To enable/disable a connection for a client, the enabled_clients property is used.

hailiang-wang commented 9 years ago

So basically, there are two objects for RESt API.

client api

what is client ? a backend application ? ==>> this is the application on our system

user api

==>> crud for current dave's users what is the user, in our case, user is dave or linda ?

lymanlai commented 9 years ago

app.use('/api/repos', require('./api/repo'));

hailiang-wang commented 9 years ago

I think it should support APIs in #91.

lymanlai commented 9 years ago

while dave use clientId, clientSecret to get the jwt the jwt will be like this:

{
  "clientId": "7e37446147bc5224fa42072f",
  "role": "appAdmin",
  "ownerId": "5596b9bd30e816d8f84bba33",
  "iat": 1436787123,
  "exp": 1436805123
}

in the auth.service.js payload._id exist => login by username, password payload.clientId exist => login by clientId, clientSecret

screen shot 2015-07-13 at 7 45 40 pm

lymanlai commented 9 years ago

how to controll which api can be access by appAdmin or admin or user

in every route

var isAuthenticated = auth.hasRole('admin');

and in config/index.js

userRoles: ['user', 'appAdmin', 'admin', 'root'],

so, while auth.hasRole('admin') then the appAdmin(which means login by clientId) can not access this route or controller

define of hasRole

function hasRole(role, checkRole) {
    return roles.indexOf(role) >= roles.indexOf(checkRole);
}

so, route with auth.hasRole('user') permission controll can be access for all login user, route with auth.hasRole('appAdmin') permission controll can be access for 'appAdmin', 'admin', 'root' route with auth.hasRole('root') permission controll only can be access by root