Skip to content

How to handle refresh token in Nuxt config with device date time is changed to previous/future time? #1886

@ChhuyChheang

Description

@ChhuyChheang

Hello, the purpose I want to allow all user login to my system with any time zone or date time. But I faced the issue after I changed any time zone or date time. I got issue with automatically refresh token after login. So I cannot successfully login to my system. Here is my Nuxt config:

import { resolve } from 'path'

require('dotenv').config()

export default {
  env: {
    BASE_URL: process.env.BASE_URL,
    IMG_URL: process.env.IMG_URL,
    UPLOAD_API: process.env.UPLOAD_API,
    REMEMBER_ME_EXPIRATION_SECONDS: process.env.REMEMBER_ME_EXPIRATION_SECONDS,
    LOGGEDIN_SESSION_EXPIRATION_SECONDS:
      process.env.LOGGEDIN_SESSION_EXPIRATION_SECONDS,
    DEBOUNCE: process.env.DEBOUNCE,
    OLD_API: process.env.OLD_API,
    X_API_KEY: process.env.X_API_KEY,
    BOOKING_WIDGET_URL: process.env.BOOKING_WIDGET_URL,
    KDS_URL: process.env.KDS_URL,
    LOYALTY_URL: process.env.LOYALTY_URL,
    ENVIRONMENT: process.env.ENVIRONMENT,
    KIOSK_URL: process.env.KIOSK_URL,
    GOOGLE_TRANSLATE_API_KEY: process.env.GOOGLE_TRANSLATE_API_KEY,
    FIREBASE_API_KEY: process.env.FIREBASE_API_KEY,
    FIREBASE_AUTH_DOMAIN: process.env.FIREBASE_AUTH_DOMAIN,
    FIREBASE_PROJECT_ID: process.env.FIREBASE_PROJECT_ID,
    FIREBASE_STORAGE_BUCKET: process.env.FIREBASE_STORAGE_BUCKET,
    FIREBASE_MESSAGING_SENDER_ID: process.env.FIREBASE_MESSAGING_SENDER_ID,
    FIREBASE_APP_ID: process.env.FIREBASE_APP_ID,
    FIREBASE_MEASUREMENT_ID: process.env.FIREBASE_MEASUREMENT_ID,
    FIREBASE_VAPID_KEY: process.env.FIREBASE_VAPID_KEY || '',
    RABBITMQ_URL: process.env.RABBITMQ_URL,
    RABBITMQ_USERNAME: process.env.RABBITMQ_USERNAME,
    RABBITMQ_PASSCODE: process.env.RABBITMQ_PASSCODE,
  },
  publicRuntimeConfig: {
    DEFAULT_ROUTE: {
      HOME: '/restaurants/overview',
      LOGIN: '/login',
      ROOT: '/',
    },
    E_BUTLER: {
      BASE_URL: process.env.E_BUTLER_URL,
    },
    BOOKING: {
      BASE_URL: process.env.BOOKING_URL,
    },
    KDS: {
      BASE_URL: process.env.KDS_URL,
    },
    LOYALTY: {
      BASE_URL: process.env.LOYALTY_URL,
    },
  },
  server: {
    host: '0.0.0.0', // default: localhost
  },

  // Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
  ssr: false,

  // Target: https://go.nuxtjs.dev/config-target
  target: 'static',

  // Global page headers: https://go.nuxtjs.dev/config-head
  head: {
    titleTemplate: '%s | Youding',
    title: process.env.TITLE,
    htmlAttrs: {
      lang: 'en',
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
      { name: 'format-detection', content: 'telephone=no' },
    ],
    link: [
      {
        rel: 'icon',
        type: 'image/x-icon',
        href: `${process.env.BASE_URL}favicon.ico`,
      },
    ],
  },

  // Global CSS: https://go.nuxtjs.dev/config-css
  css: [
    'vue-scroll-picker/dist/style.css',
    'vue-advanced-cropper/dist/style.css',
  ],

  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: [
    '~/plugins/api.ts',
    // Packages
    '~/plugins/packages/vue-flag-icon.js',
    '~/plugins/packages/lodash.ts',
    '~/plugins/packages/qr-code.js',
    '~/plugins/packages/vuedraggable.ts',
    '~/plugins/packages/vue-scroll-picker.ts',
    '~/plugins/packages/vue-html2pdf.ts',
    '~/plugins/packages/vuetify-tiptap.ts',
    '~/plugins/packages/fingerprint.client.ts',
    // Utilties
    '~/plugins/utility/getBase64.ts',
    '~/plugins/utility/asset.ts',
    '~/plugins/utility/convertPrice.ts',
    '~/plugins/utility/imgUrl.ts',
    '~/plugins/utility/convertThumbnail.ts',
    '~/plugins/utility/dateRangeGenerate.ts',
    '~/plugins/utility/isValidUrl.ts',
    '~/plugins/utility/networkStatus.ts',
    '~/plugins/utility/firebase.ts',
    '~/plugins/utility/rabbitMQ.ts',
    '~/plugins/utility/deviceTimeCheck.ts',
    // Directives
    '~/plugins/directives/menuIndicator.ts',
    '~/plugins/directives/offlineGuard.ts',
  ],

  // Auto import components: https://go.nuxtjs.dev/config-components
  components: true,

  // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
  buildModules: [
    // https://go.nuxtjs.dev/typescript
    '@nuxt/typescript-build',
    // https://go.nuxtjs.dev/vuetify
  ],

  // Modules: https://go.nuxtjs.dev/config-modules
  modules: [
    // https://go.nuxtjs.dev/axios
    '@nuxtjs/axios',
    '@nuxtjs/auth-next',
    '@nuxtjs/i18n',
    '@nuxtjs/proxy',
    '@nuxtjs/vuetify',
  ],

  i18n: {
    strategy: 'no_prefix',
    locales: [
      { code: 'en', iso: 'en-US', file: 'en.json' },
      { code: 'fr', iso: 'fr-FR', file: 'fr.json' },
      { code: 'km', iso: 'km-KH', file: 'km.json' },
      { code: 'zh-Hans', iso: 'zh-Hans', file: 'zh-Hans.json' },
      { code: 'vi', iso: 'vi-VN', file: 'vi.json' },
      { code: 'th', iso: 'th-TH', file: 'th.json' },
      { code: 'ja', iso: 'ja-JP', file: 'ja.json' },
    ],
    langDir: '~/locales/',
    defaultLocale: 'en',
    vueI18n: {
      fallbackLocale: 'en',
    },
  },

  // Axios module configuration: https://go.nuxtjs.dev/config-axios
  axios: {
    // Workaround to avoid enforcing hard-coded localhost:3000: https://github.com/nuxt-community/axios-module/issues/308
    baseURL: process.env.API,
  },

  // Vuetify module configuration: https://go.nuxtjs.dev/config-vuetify
  vuetify: {
    optionsPath: '~/vuetify.options.js',
    treeShake: true,
    customVariables: ['~/assets/variables.scss'],
  },

  // Build Configuration: https://go.nuxtjs.dev/config-build
  build: {
    transpile: ['vuetify', '@peepi/vuetify-tiptap', 'firebase'],
    babel: {
      compact: true,
    },
  },
  router: {
    middleware: [
      'auth',
      // 'delay-auth',
      'remember',
      'refresh',
      'superadmin',
      'check-permission',
      'check-license',
      'date-filter',
    ],
    base: process.env.BASE_URL || '/',
  },

  // @nuxtjs/auth-next
  auth: {
    cookie: {
      prefix: 'auth.',
      options: {
        // maxAge: 60 * 5, // This is global maxAge for both access_token and refresh_token. Please check the middleware of remember.js to see how we handle maxAge when user click on remembe me.
      },
    },
    watchLoggedIn: true,
    rewriteRedirects: true,
    strategies: {
      local: {
        scheme: 'refresh', // this configuration tells our Vue app to follow refresh token scheme.
        token: {
          property: 'data.token', // this is the access_token property name of the server response { success: true, data: { access_token : '...'}}
          global: true,
          // maxAge: 60 * 5,
        },
        refreshToken: {
          property: 'data.refresh_token', // this is the refresh_token property name of the server response { success: true, data: { refresh_token : '...'}}
          data: 'token', // this is the refresh_token property name of the request payload to the server to refresh new token { token : '....' }
          // maxAge: 60 * 43200,
        },
        // autoRefresh: {
        //   enable: true,
        //   margin: 60, // refresh 60 seconds before token expiry
        // },
        endpoints: {
          login: {
            url: '/switch-restaurant',
            method: 'post',
          },
          refresh: {
            url: '/refresh', // this url tells our Vue app which endpoint to refresh token, once it is expierd.
            method: 'post',
          },
          logout: {
            url: '/logout',
            method: 'post',
          },
          user: {
            url: '/me',
            method: 'get',
          },
        },
        user: {
          property: 'data',
          autoFetch: false,
        },
        autoLogout: true, // this configuration tells our Vue app to force logout when cookie or session are expired.
      },
      embed: {
        scheme: resolve(__dirname, './utils/embedScheme.ts'),
        token: {
          property: 'data.token',
          global: true,
        },
        endpoints: {
          login: {
            url: '/login',
            method: 'post',
          },
          logout: {
            url: '/logout',
            method: 'post',
          },
          user: {
            url: '/me',
            method: 'get',
          },
        },
        user: {
          property: 'data',
          autoFetch: false,
        },
      },
    },
    // Redirect configuration is not working well yet. We have to manually redirect after login/logout using this.$router.push()
    redirect: {
      login: '/login',
      logout: false,
      callback: '/login',
      home: '/restaurants/overview',
    },
  },
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions