Giter Site home page Giter Site logo

adonis5-jwt's Introduction

adonis5-jwt

npm-image license-image typescript-image

Add JWT authentication to Adonisjs v5. Thanks to https://github.com/alex-oliveira for the starting implementation!

Installation

Make sure to install and configure @adonisjs/auth and @adonisjs/lucid beforehand, by running the following commands:

npm install @adonisjs/auth @adonisjs/lucid 
//Or, with yarn: yarn add @adonisjs/auth @adonisjs/lucid

node ace configure @adonisjs/auth
node ace configure @adonisjs/lucid

Install adonis5-jwt via npm or yarn:

npm install adonis5-jwt
//Or, with yarn: yarn add adonis5-jwt

Configure package

After the package has been installed, you have to configure it by running a command:

node ace configure adonis5-jwt

This will ask a few questions and modify adonisjs files accordingly.

During this configure, you will have to choose whether you want to store JWT in database or not. The two solutions have advantages and disadvantages. Bear in mind that the default is NOT to store JWT in db.

Command JWT in db JWT not in db
recommended solution
refresh token stored in DB
full control on JWT expiration/revocation
faster login that doesn't use DB
logout doesn't need refresh token

Usage

JWT authentication implements the same methods that other guards in @adonisjs/auth implements, so you can call .authenticate(), .generate() etc.

Just make sure to prepend .use("jwt"):

//authenticate() example
Route.get('/dashboard', async ({ auth }:HttpContextContract) => {
    await auth.use("jwt").authenticate();
    const userModel = auth.use("jwt").user!;
    const userPayloadFromJwt = auth.use("jwt").payload!;
});

//generate() example:
Route.get('/login', async ({ auth }:HttpContextContract) => {
    const user = await User.find(1);
    const jwt = await auth.use("jwt").generate(user);
    //or using .login():
    //const jwt = await auth.use("jwt").login(user);
});

//refresh token usage example:
Route.post('/refresh', async ({ auth, request }:HttpContextContract) => {
    const refreshToken = request.input("refresh_token");
    const jwt = await auth.use("jwt").loginViaRefreshToken(refreshToken);
});

Route.post('/logout', async ({ auth, response }:HttpContextContract) => {
  await auth.use('jwt').revoke()
  return {
    revoked: true
  }
})

By default, .generate() or .login() uses a payload like the following:

//user is a Lucid model
{
    userId: user.id,
    user: {
        name: user.name,
        email: user.email,
    },
}

If you want to generate a JWT with a different payload, simply specify payload when calling .generate() or .login():

await auth.use("jwt").login(user, {
    payload: {
        email: user.email,
    },
});

With the refresh token, you can obtain a new JWT using loginViaRefreshToken():

const refreshToken = request.input("refresh_token");
await auth.use("jwt").loginViaRefreshToken(refreshToken, {
    payload: {
        email: user.email,
    },
});

adonis5-jwt's People

Contributors

maxgalbu avatar ruslankarelin 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

Watchers

 avatar  avatar  avatar

adonis5-jwt's Issues

Passphrase required for encrypted key

Hi. I try to use this package for authenticate in microservice. JWT token generated by Symfony app with passphrase. await auth.use('jwt').authenticate() except passphrase's error.

[1660925432779] ERROR (server/12898 on Ba-Anh-MacBook-Pro.local): Passphrase required for encrypted key
    err: {
      "type": "TypeError",
      "message": "Passphrase required for encrypted key",
      "stack":
          TypeError: Passphrase required for encrypted key
              at createPrivateKey (internal/crypto/keys.js:351:10)
              at JWTGuard.generateKey (/Users/doanbaanh/PhpStormProjects/gold/server/node_modules/adonis5-jwt/build/lib/Guards/JwtGuard.js:341:46)
              at JWTGuard.verifyToken (/Users/doanbaanh/PhpStormProjects/gold/server/node_modules/adonis5-jwt/build/lib/Guards/JwtGuard.js:392:29)
              at JWTGuard.authenticate (/Users/doanbaanh/PhpStormProjects/gold/server/node_modules/adonis5-jwt/build/lib/Guards/JwtGuard.js:118:36)
              at AppController.playerHistory (/Users/doanbaanh/PhpStormProjects/gold/server/app/Controllers/Http/AppController.ts:8:27)
              at Injector.callAsync (/Users/doanbaanh/PhpStormProjects/gold/server/node_modules/@adonisjs/fold/build/src/Ioc/Injector.js:124:30)
              at processTicksAndRejections (internal/process/task_queues.js:95:5)
      "code": "ERR_MISSING_PASSPHRASE",
      "status": 500
    }

How can I fix this? Thanks.

Invalid auth config, missing "provider" or "provider.driver" property

I am getting this error and don't know how to resolve this error since my contract auth.ts looks like this

/**
 * Contract source: https://git.io/JvyKD
 *
 * Feel free to let us know via PR, if you find something broken in this
 * file.
 */

import CmsUser from 'App/Models/System/CmsUser'
import { JWTGuardConfig, JWTGuardContract } from "@ioc:Adonis/Addons/Jwt";

import ApiUsers from 'App/Models/Api/ApiUser'

declare module '@ioc:Adonis/Addons/Auth' {
  /*
  |--------------------------------------------------------------------------
  | Providers
  |--------------------------------------------------------------------------
  |
  | The providers are used to fetch users. The Auth module comes pre-bundled
  | with two providers that are `Lucid` and `Database`. Both uses database
  | to fetch user details.
  |
  | You can also create and register your own custom providers.
  |
  */
  interface ProvidersList {
    /*
    |--------------------------------------------------------------------------
    | User Provider
    |--------------------------------------------------------------------------
    |
    | The following provider uses Lucid models as a driver for fetching user
    | details from the database for authentication.
    |
    | You can create multiple providers using the same underlying driver with
    | different Lucid models.
    |
    */
    user: {
      implementation: LucidProviderContract<typeof CmsUser>,
      config: LucidProviderConfig<typeof CmsUser>,
    }
    user_using_database: {
      implementation: DatabaseProviderContract<ApiUsers>,
      config: DatabaseProviderConfig,
    };
  }

  /*
  |--------------------------------------------------------------------------
  | Guards
  |--------------------------------------------------------------------------
  |
  | The guards are used for authenticating users using different drivers.
  | The auth module comes with 4 different guards.
  |
  | - SessionGuardContract
  | - BasicAuthGuardContract
  | - JwtGuardContract
  | - OATGuardContract ( Opaque access token )
  |
  | Every guard needs a provider for looking up users from the database.
  |
  */
  interface GuardsList {
    /*
    |--------------------------------------------------------------------------
    | Web Guard
    |--------------------------------------------------------------------------
    |
    | The web guard uses sessions for maintaining user login state. It uses
    | the `user` provider for fetching user details.
    |
    */
    web: {
      implementation: SessionGuardContract<'user', 'web'>,
      config: SessionGuardConfig<'user'>,
    }
    jwt: {
      implementation: JWTGuardContract<'user_using_database', 'api'>,
      config: JWTGuardConfig<'user_using_database'>,
    };
  }
}

and my config/auth.ts looks like this

/**
 * Config source: https://git.io/JvyKy
 *
 * Feel free to let us know via PR, if you find something broken in this config
 * file.
 */

import { AuthConfig } from '@ioc:Adonis/Addons/Auth'

/*
|--------------------------------------------------------------------------
| Authentication Mapping
|--------------------------------------------------------------------------
|
| List of available authentication mapping. You must first define them
| inside the `contracts/auth.ts` file before mentioning them here.
|
*/
const authConfig: AuthConfig = {
  guard: 'web',
  list: {
    /*
    |--------------------------------------------------------------------------
    | Web Guard
    |--------------------------------------------------------------------------
    |
    | Web guard uses classic old school sessions for authenticating users.
    | If you are building a standard web application, it is recommended to
    | use web guard with session driver
    |
    */
    web: {
      driver: 'session',

      provider: {
        /*
        |--------------------------------------------------------------------------
        | Driver
        |--------------------------------------------------------------------------
        |
        | Name of the driver
        |
        */
        driver: 'lucid',

        /*
        |--------------------------------------------------------------------------
        | Identifier key
        |--------------------------------------------------------------------------
        |
        | The identifier key is the unique key on the model. In most cases specifying
        | the primary key is the right choice.
        |
        */
        identifierKey: 'id',

        /*
        |--------------------------------------------------------------------------
        | Uids
        |--------------------------------------------------------------------------
        |
        | Uids are used to search a user against one of the mentioned columns. During
        | login, the auth module will search the user mentioned value against one
        | of the mentioned columns to find their user record.
        |
        */
        uids: ['email'],

        /*
        |--------------------------------------------------------------------------
        | Model
        |--------------------------------------------------------------------------
        |
        | The model to use for fetching or finding users. The model is imported
        | lazily since the config files are read way earlier in the lifecycle
        | of booting the app and the models may not be in a usable state at
        | that time.
        |
        */
        model: () => import('App/Models/System/CmsUser'),
      },
    },
    jwt: {
      serializer: 'lucid',
      model: 'App/Models/ApiUser',
      scheme: 'jwt',
      uid: 'email',
      password: 'password',
      options: {
        secret: 'sP5j9XnCe1oBU44dsHWV3iajXnTxghF'
      }
    },

  },

}

export default authConfig

Please help me out

What is token ?

Hi admin, i have a question :
image

what mean token in table "jwt_tokens"

Revoke method doesn't work

Hi,

When I call the revoke method I get an error message saying: Empty or no refresh token passed.

The code is exactly like in the docs:

 public async logout({ auth }) {
    await auth.use('jwt').revoke();

    return {
      revoked: true
    };
  }

Is there an issue with it or am I doing something wrong?

Logout isn't working

Hi, thanks for develop this feature, I really needed this, unfortunately logout isn't working for me, my code is basically the same as your docs, but my token are not been removed from database after revoke method

  public async logout({ auth }: HttpContextContract) {
    await auth.use('jwt').revoke()
    return {
      revoked: true,
    }
  }

After run the method above, I still can use the same token and nothing changes on jwt_tokens table.
Can you check if is any problem with revoke() method?

My config file is like this:

const authConfig: AuthConfig = {
  guard: 'jwt',
  guards: {
    api: {
      driver: 'oat',
      tokenProvider: {
        type: 'api',
        driver: 'redis',
        redisConnection: 'local',
        foreignKey: 'user_id',
      },
      provider: {
        driver: 'lucid',
        identifierKey: 'id',
        uids: ['email'],
        model: () => import('App/Models/User'),
      },
    },
    jwt: {
      driver: 'jwt',
      publicKey: Env.get('JWT_PUBLIC_KEY', '').replace(/\\n/g, '\n'),
      privateKey: Env.get('JWT_PRIVATE_KEY', '').replace(/\\n/g, '\n'),
      tokenProvider: {
        type: 'jwt',
        driver: 'database',
        table: 'jwt_tokens',
        foreignKey: 'user_id',
        refreshTokenKey: 'refresh_token',
        // redisConnection: 'local',
      },
      provider: {
        driver: 'lucid',
        identifierKey: 'id',
        uids: ['email'],
        model: () => import('App/Models/User'),
      },
    },
  },
}

And my contract is:

declare module '@ioc:Adonis/Addons/Auth' {
  interface ProvidersList {
    user: {
      implementation: LucidProviderContract<typeof User>
      config: LucidProviderConfig<typeof User>
    }
  }

  interface GuardsList {
    api: {
      implementation: OATGuardContract<'user', 'api'>
      config: OATGuardConfig<'user'>
    }
    jwt: {
      implementation: JWTGuardContract<'user', 'jwt'>
      config: JWTGuardConfig<'user'>
    }
  }
}

Expected to find namespace named ''@ioc:Adonis/Addons/Auth''

I have installed @adonisjs/auth and @adonisjs/lucid but this thing happen when i do the node ace configure adonis5-jwt and i don't know why

   Error: Expected to find namespace named ''@ioc:Adonis/Addons/Auth''.
 

   ⁃ Object.throwIfNullOrUndefined
     .../node_modules/.pnpm/@[email protected]/node_modules/@ts-morph/common/dist/ts-morph-common.js:469
   ⁃ SourceFile.getModuleOrThrow
     .../node_modules/.pnpm/[email protected]/node_modules/ts-morph/dist/ts-morph.js:11160
   ⁃ getDefinedProviders
     .../node_modules/.pnpm/[email protected]/node_modules/adonis5-jwt/build/instructions.js:127

decode jwt

i would decode the jwt to get informations is it already possible? I find nothing about

Trying to create a brand new token from login results in E_INVALID_TOKEN_EXPIRY

export default class AuthenticationController {
  public async signUp({ request, response, auth }: HttpContextContract) {
    const { email, password } = await request.validate(SignUpUser);

    const user = new User();

    user.email = email;
    user.password = password;

    try {
      await user.save();

      const jwt = await auth.use('jwt').generate(user);
      return jwt;
    } catch (error) {
      console.log(error);
      return response.badRequest('Invalid credentials ');
    }
  }
}
    jwt: {
      driver: 'jwt',
      publicKey: Env.get('JWT_PUBLIC_KEY', '').replace(/\\n/g, '\n'),
      privateKey: Env.get('JWT_PRIVATE_KEY', '').replace(/\\n/g, '\n'),
      persistJwt: false,
      jwtDefaultExpire: '10m',
      refreshTokenDefaultExpire: '1d',
      tokenProvider: {
        type: 'jwt',
        driver: 'redis',
        redisConnection: 'local',
        foreignKey: 'user_id'
      },
      provider: {
        driver: 'lucid',
        identifierKey: 'id',
        uids: [],
        model: () => import('App/Models/User')
      }
    }
Exception: E_INVALID_TOKEN_EXPIRY: The refresh token expiry date/time should be in the future
    at JwtRedisProvider.write (/Users/z/project/node_modules/adonis5-jwt/build/lib/TokenProviders/JwtRedisProvider.js:99:19)
    at JWTGuard.login (/Users/z/project/node_modules/adonis5-jwt/build/lib/Guards/JwtGuard.js:228:38)
    at AuthenticationController.signUp (/Users/z/project/app/Controllers/Http/AuthenticationController.ts:17:19)
    at Object.PreCompiler.runRouteHandler [as fn] (/Users/z/project/node_modules/@adonisjs/http-server/build/src/Server/PreCompiler/index.js:47:31)
    at Server.handleRequest (/Users/z/project/node_modules/@adonisjs/http-server/build/src/Server/index.js:108:13)

If I change persistJwt: false to persistJwt: true it works as expected.

I also had to install @adonis/sink into my application to run node ace configure adonis5-jwt even though yarn why @adonis/sink showed the dependency was installed by adonis.

How to set jti and custom properties

I try to set jti like this but it not working

auth.use("jwt").generate(user, {
  payload: {
      name: user.name,
      email: user.email,
      
  },
  jti: hash,
  token_type: "access"
})

Error: No provider implementation found in ProvidersList. Maybe you didn't configure @adonisjs/auth first?

This does not work with custom User provider

  interface ProvidersList {
    /*
    |--------------------------------------------------------------------------
    | User Provider
    |--------------------------------------------------------------------------
    |
    | The following provider directlly uses Database query builder for fetching
    | user details from the database for authentication.
    |
    | You can create multiple providers using the same underlying driver with
    | different database tables.
    |
    */
    user: {
      implementation: CustomAuthProvider
      config: CustomAuthProviderConfig
    }
  }

Not implemented newline kind: undefined

I'm getting this error after running the node ace configure adonis5-jwt

Steps done:

  1. install the adonis5-jwt with npm install adonis5-jwt
  2. run the node ace configure adonis5-jwt

Here's the error logs after running the node ace configure adonis5-jwt

Run `npm audit` for details.
➜  testapp-api git:(testing) ✗ node ace configure adonis5-jwt
❯ Select provider for finding users · user
❯ Do you want to persist JWT in database/redis (please read README.md beforehand)? (y/N) · true
❯ Select the provider for storing JWT tokens · redis
❯ Enter the default expire time for the JWT (10h = 10 hours, 5d = 5 days, etc) · 1d
❯ Enter the default expire time for the refresh token (10h = 10 hours, 5d = 5 days, etc) · 1d
UPDATE: .env,.env.example

  Error 

 Not implemented newline kind: undefined


   1  newLineKindToString
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:379

   2  ManipulationSettingsContainer.getNewLineKindAsString
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:259

   3  ProjectContext.createWriter
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:19554

   4  SourceFile._getWriter
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:3962

   5  SourceFile._getWriterWithChildIndentation
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:3944

   6  getNewText
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:2492

   7  insertIntoBracesOrSourceFile
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:2484

   8  insertIntoBracesOrSourceFileWithGetChildren
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:2516

   9  SourceFile._insertChildren
     /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:11299

   10  SourceFile.insertImportDeclarations
      /Users/joeneldeasis/Projects/testapp-api/node_modules/ts-morph/dist/ts-morph.js:9002

➜  testapp-api git:(testing) ✗ 

mongodb token

I'm followed this project:

Auth-mongoose-provider

everything worked fine.

but token is still trying to access config/database.ts.

what's the right way of registering the provider for the token?

Login Via Refresh Token, this error appear and my jwt token on db deleted

when i call

const refreshToken = await request.input("refresh_token"); 
const jwt = await auth.use("jwt").loginViaRefreshToken(refreshToken); <-- error here
response.status(200).json({
      message: "refresh token!.",
      data: jwt
    })

whats wrong with it ?

this response i get :

{
    "message": "Auth database provider expects \"users.id\" to always exist",
    "stack": "Exception: Auth database provider expects \"users.id\" to always exist\n    at DatabaseProvider.ensureUserHasId (/home/ifuu/Work/adonis/restful_API/node_modules/@adonisjs/auth/build/src/UserProviders/Database/index.js:60:19)\n    at DatabaseProvider.getUserFor (/home/ifuu/Work/adonis/restful_API/node_modules/@adonisjs/auth/build/src/UserProviders/Database/index.js:79:14)\n    at JWTGuard.getUserForLogin (/home/ifuu/Work/adonis/restful_API/node_modules/@adonisjs/auth/build/src/Guards/Base/index.js:98:50)\n    at JWTGuard.login (/home/ifuu/Work/adonis/restful_API/node_modules/adonis5-jwt/build/lib/Guards/JwtGuard.js:198:41)\n    at JWTGuard.loginViaRefreshToken (/home/ifuu/Work/adonis/restful_API/node_modules/adonis5-jwt/build/lib/Guards/JwtGuard.js:166:21)\n    at processTicksAndRejections (internal/process/task_queues.js:95:5)\n    at AuthController.refresh (/home/ifuu/Work/adonis/restful_API/app/Controllers/Http/AuthController.ts:45:17)\n    at Object.PreCompiler.runRouteHandler [as fn] (/home/ifuu/Work/adonis/restful_API/node_modules/@adonisjs/http-server/build/src/Server/PreCompiler/index.js:47:31)\n    at Server.handleRequest (/home/ifuu/Work/adonis/restful_API/node_modules/@adonisjs/http-server/build/src/Server/index.js:108:13)"
}

Error login !!

When you use a email as Uid, always take the first result from the database, and the first password, doesnt work with another users, if you try to login with other email, but ussing the password of first user on database, this allow login !!

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.