0.1.0 • Published 6 years ago

@abramltd/jwt-oauth2-middleware v0.1.0

Weekly downloads
-
License
ISC
Repository
github
Last release
6 years ago

JWT OAUTH Middleware

This project defines some middleware for the creation of OAuth Server using oauth2-node. An example is given using express as the intended server. Currently only password and refresh_token grants are supported.

Usage & routes

Short usage version (example with express.js server):

    var oauth = require('insert-package-name')(model, config); // creating server middleware
    ... // express needed stuff

    app.post('/oauth/token', oauth.token); // (1) and (2)

    app.get('/validate', oauth.authenticate, function (req, res) { // (3)
        res.json({ message: 'Secure data' });
    });

Any OAuth server that implements password and refresh_token grant types, needs to have three routes:

  • one for generating access tokens (1)
  • one for generating new access tokens from unexpired refresh tokens (2)
  • one for token validation/gathering sensitive information (3)

Generating access tokens

Usually, the route for acquiring an access token for a user is /token. The request needs to be HTTP/HTTPS POST and required data is sent in the request's body.

Required dataValue
usernameuser's account username
client_idId of the client (application) that is requesting the user's access token
passworduser's account password
grant_typepassword
client_secretclient's secret used to sign token data
scopethe scope the generated access token needs to have

The return value example is shown below.

    {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjEyMzUiLCJ1c2VySWQiOiI1OGVkMDUwYTczNGQxZDBlNjVmYzc3OTQiLCJ0eXBlIjoiYWNjZXNzVG9rZW4iLCJ1c2VybmFtZSI6IkRhbmEiLCJiYW5hbmEiOiJiYW5hbmEgd2hvIiwic2NvcGUiOiJiYW5hbmEiLCJleHBpcmVEYXRlIjoxNDk4MzI4MjY3NDc2LCJpYXQiOjE0OTgzMjgyMDcsImV4cCI6MTQ5ODMyODI2N30.KygbmACDVPYGoDpUg7YiyI5oAzQ5aUv8uqG0m9BDNg4",
        "token_type": "Bearer",
        "expires_in": 59, // seconds 
        "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjEyMzUiLCJ1c2VySWQiOiI1OGVkMDUwYTczNGQxZDBlNjVmYzc3OTQiLCJ0eXBlIjoicmVmcmVzaFRva2VuIiwidXNlcm5hbWUiOiJEYW5hIiwiYmFuYW5hIjoiYmFuYW5hIHdobyIsInNjb3BlIjoiYmFuYW5hIiwiZXhwaXJlRGF0ZSI6MTQ5ODMyODI2NzQ3OCwiaWF0IjoxNDk4MzI4MjA3LCJleHAiOjE0OTgzMjgyNjd9.milncP0uopHUEU56ZqG1i9IDKDkP5ANfPQPFazMZLTE",
        "scope": "banana"
    }

Generating new access tokens from unexpired refresh tokens

Usually, the route for acquiring an access token for a user is /token. The request needs to be HTTP/HTTPS POST and required data is sent in the request's body.

Required dataValue
client_idId of the client (application) that is requesting the refresh of the user's access token
grant_typerefresh_token
client_secretclient's secret used to sign data, secret of the refresh token
refresh_tokenrefresh token used to retrieve the new access and refresh token. Musn't be expired

Remark: if the token isn't expired, it will be revoked and a new pair accessToken/refreshToken will be issued. In addition, the new generated tokens will have the same scope as the previously generated ones. An example is shown below.

    {
        "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjEyMzUiLCJ1c2VySWQiOiI1OGVkMDUwYTczNGQxZDBlNjVmYzc3OTQiLCJ0eXBlIjoiYWNjZXNzVG9rZW4iLCJ1c2VybmFtZSI6IkRhbmEiLCJiYW5hbmEiOiJiYW5hbmEgd2hvIiwic2NvcGUiOiJiYW5hbmEiLCJleHBpcmVEYXRlIjoxNDk4MzI5MTY3OTkxLCJpYXQiOjE0OTgzMjkxMDcsImV4cCI6MTQ5ODMyOTE2N30._vbYF3f1DIcuiG_nX-8clYX6IgckIqY9n75NoLzw3tE",
        "token_type": "Bearer",
        "expires_in": 59, // seconds
        "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRJZCI6IjEyMzUiLCJ1c2VySWQiOiI1OGVkMDUwYTczNGQxZDBlNjVmYzc3OTQiLCJ0eXBlIjoicmVmcmVzaFRva2VuIiwidXNlcm5hbWUiOiJEYW5hIiwiYmFuYW5hIjoiYmFuYW5hIHdobyIsInNjb3BlIjoiYmFuYW5hIiwiZXhwaXJlRGF0ZSI6MTQ5ODMyOTE2Nzk5MywiaWF0IjoxNDk4MzI5MTA3LCJleHAiOjE0OTgzMjkxNjd9.GQU0bCFlu_qCuQgZtdTXTie6SPA08xVIv5Zv93ELFig",
        "scope": "banana"
    }

Token validation/gathering sensitive information

For validating the token or gathering sensitive information one must issue a HTTP GET request on a desired route. If scope should be validated, the request should have scope specified in the URL query. Query parameter's name is scope.

Model

In order to create the middleware object one must supply the model object and configuration. However, not all model functions need to be provided - partial functionality is provided. The following table shows which grant_types require which methods as well as show if the method is used in (1), (2) or (3).

Model function nameDeclarationDescriptionGrant typesNeeded for (1)?Needed for (2)?Needed for (3)?
generateTokenData(client, user, scope) => data directly saved into the tokenSame for access token and refresh tokenBothyesyesno
getClientById(id) => Client : {id: string, refreshTokenSecret: string, accessTokenSecret: string}Returns client objectBothyesyesyes
getUserData(username, password) => either (User : {id: string}) or falseReturns user objectpasswordyesyesno
revokeRefreshToken(data) => booleanRevokes the supplied refresh token and returns whether the operation was successfulrefresh_tokennoyesno
saveToken(token, user, client) => Token with user and client data attached as follows {user: {id: string}, client: {id: string}}Saves both refresh and access tokensBothyesyesno
validateScopeUser(user, client, scope)=> either scope or falseUsed to see whether the user/client combination should/can have certain scopepasswordyesnono
verifyScopeAccessToken(data, scope) => booleanUsed to see whether the supplied access token can be used for the supplied scopeAuthenticate methodnonoyes

revokeRefreshToken data type

 
  data = { 
      user: {id: string},
      client: {id: string},
      token: {
                    refreshToken: string, // token
                    expires: Date,
                    client: Client,
                    scope: string
      },
      scope: string
    };

verifyScopeAccessToken data type

 
  data = {
            user: { id: string},
            token: {
                accessToken: string, //bearerToken,
                expires: Date,
                client: Client,
                scope: string
            },
            scope: string
 };

Config

Config needs to define expiration in seconds for both access and refresh token. Example is provided below.


 var config = {
   accessTokenExpiry: 60,             // seconds
   refreshTokenExpiry: 60,          // seconds
 };