maxgalbu / adonis5-jwt

JWT Authentication service for Adonisjs v5
MIT License
86 stars 15 forks source link

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

Closed IfuuIbad closed 2 years ago

IfuuIbad commented 2 years ago

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)"
}
maxgalbu commented 2 years ago

Hi @IfuuIbad, please paste:

IfuuIbad commented 2 years ago

users model

import { DateTime } from 'luxon'
import Hash from '@ioc:Adonis/Core/Hash'
import { BaseModel, column, beforeSave } from '@ioc:Adonis/Lucid/Orm'

export default class Users extends BaseModel {
  public static table = 'users'

  @column({ isPrimary: true })
  public id: number

  @column()
  public email: string

  @column({ serializeAs: null })
  public password: string

  @column()
  public remember_me_token: string

  @column.dateTime({ autoCreate: true })
  public createdAt: DateTime

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  public updatedAt: DateTime

  @beforeSave()
  public static async hashPassword(user: Users) {
    if (user.$dirty.password) {
      user.password = await Hash.make(user.password)
    }
  }
}
IfuuIbad commented 2 years ago

auth.ts

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

import { AuthConfig } from '@ioc:Adonis/Addons/Auth'
import Env from "@ioc:Adonis/Core/Env";

/*
|--------------------------------------------------------------------------
| 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: 'api',
  guards: {
    /*
    |--------------------------------------------------------------------------
    | OAT Guard
    |--------------------------------------------------------------------------
    |
    | OAT (Opaque access tokens) guard uses database backed tokens to authenticate
    | HTTP request. This guard DOES NOT rely on sessions or cookies and uses
    | Authorization header value for authentication.
    |
    | Use this guard to authenticate mobile apps or web clients that cannot rely
    | on cookies/sessions.
    |
    */
    api: {
      driver: 'oat',

      /*
      |--------------------------------------------------------------------------
      | Tokens provider
      |--------------------------------------------------------------------------
      |
      | Uses SQL database for managing tokens. Use the "database" driver, when
      | tokens are the secondary mode of authentication.
      | For example: The Github personal tokens
      |
      | The foreignKey column is used to make the relationship between the user
      | and the token. You are free to use any column name here.
      |
      */
      tokenProvider: {
        type: 'api',
        driver: 'database',
        table: 'api_tokens',
        foreignKey: 'user_id',
      },

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

        /*
        |--------------------------------------------------------------------------
        | Identifier key
        |--------------------------------------------------------------------------
        |
        | The identifier key is the unique key inside the defined database table.
        | 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'],

        /*
        |--------------------------------------------------------------------------
        | Database table
        |--------------------------------------------------------------------------
        |
        | The database table to query. Make sure the database table has a `password`
        | field and `remember_me_token` column.
        |
        */
        usersTable: 'users',
      },
    },
    /*
    |--------------------------------------------------------------------------
    | Basic Auth Guard
    |--------------------------------------------------------------------------
    |
    | Uses Basic auth to authenticate an HTTP request. There is no concept of
    | "login" and "logout" with basic auth. You just authenticate the requests
    | using a middleware and browser will prompt the user to enter their login
    | details
    |
    */
    basic: {
      driver: 'basic',
      realm: 'Login',

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

        /*
        |--------------------------------------------------------------------------
        | Identifier key
        |--------------------------------------------------------------------------
        |
        | The identifier key is the unique key inside the defined database table.
        | 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'],

        /*
        |--------------------------------------------------------------------------
        | Database table
        |--------------------------------------------------------------------------
        |
        | The database table to query. Make sure the database table has a `password`
        | field and `remember_me_token` column.
        |
        */
        usersTable: 'users',
      },
    },
    jwt: {
      driver: "jwt",
      publicKey: Env.get('JWT_PUBLIC_KEY', '').replace(/\\n/g, '\n'),
      privateKey: Env.get('JWT_PRIVATE_KEY', '').replace(/\\n/g, '\n'),
      persistJwt: true,
      jwtDefaultExpire: '7d',
      refreshTokenDefaultExpire: '10d',
      tokenProvider: {
        type: 'api',
        driver: 'database',
        table: 'jwt_tokens',
        foreignKey: 'user_id'
      },
      provider: {
        driver: 'database',
        identifierKey: 'id',
        uids: ['email'],
        usersTable: 'users'
      }
    },
  },
}

export default authConfig
IfuuIbad commented 2 years ago

example of generated jwt

{
"message": "Success Login!.",
    "data": {
        "type": "bearer",
        "token": "eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7InVzZXJJZCI6MSwidXNlciI6eyJlbWFpbCI6InRlc3RAYWRvbmlzanMuY29tIn19LCJpYXQiOjE2MzkxNDMxOTgsImV4cCI6MTYzOTc0Nzk5OH0.V0fOwJPcodZGoU-2dAZY6Li8nXaDwWg0Zf2G3WbxHfd41YhU-41iHEqiQWwK5ed36L4ByJW7wsB3Qr6FZtG4s4GfOxuc9H3OnvDumy9cUlsX6fsNr13aHMnXau74vmH_PslhUMkR7zpo1hPM7ugcsgAmPwP1XOfkIIkUAfvM31lmk-50M3ges1aioeJFM9wa2apbIWFy3gbVMeV7oGWgoWsJo6TqVUDvtsvDfNXv69uqGMKF-Uum-WDjAC0mjuUIfqRJB5JlKIbJ8SHmP0reWBnnOuv5ZYa21jeJ87XshNbfW68YHIcSNbHJOXwMRVdpOUvN5TMN7PQ622cjL8UNOoAjXXPV_V0krIyFJ2Df13EuJL9pVa228-46ry51Sc54O-7Nf0UYeF7zfV48WV9ck6Vnf9-ofUK7wSAcHEsjSYNR8BbSF7QF-t-M-Pej8ki6vL3GajIxzjtGq0hjNQSRY_EwrHX5kveKOczAxcOJhiuiqzi3JLCXuOEtMh58cQl7dtYusrE196Mj0um2HVJQ0jtbzA4YtNPRVIQQjg0yKU8p9RY0Rc96fWB_jsaXhseNh1jdR81Kyu0ZS-PwLUZ6VYIzXsXXoIOzk28LJlkKKnZTZmjTSW8PBpdsI2nMR8pO31BEH_8Fc7b8sgv6F_q-q2MkiWhy7Me_I-vnojfZ26c",
        "refreshToken": "a45327e439bbe4972123e5b87f8a0b3de99402d8c1ca3cd8e6d7b0df45f68957",
        "expires_at": "2021-12-17T20:33:18.656+07:00"
    }
}
maxgalbu commented 2 years ago

I can reproduce it. Let me check it

maxgalbu commented 2 years ago

Here's the fix: 3b5dc5e

Pushed 1.1.3 with the fix