nuxt-community / auth-module

Zero-boilerplate authentication support for Nuxt 2
https://auth.nuxtjs.org
MIT License
1.93k stars 924 forks source link

Extend Laravel Sanctum scheme/provider to support 2FA #1707

Closed sts-ryan-holton closed 2 years ago

sts-ryan-holton commented 2 years ago

I'm trying to get 2FA working with my Laravel Sanctum provider in my project. Previously I was using the local scheme and had 2FA working by creating a custom scheme and adding a block of code after the main request to return a response, I will attach this now:

custom scheme for Local

import { LocalScheme } from '~auth/runtime'

export default class CustomScheme extends LocalScheme {

  async login(endpoint, reset = true) {
    if (!this.options.endpoints.login) {
      return
    }

    // Ditch any leftover local tokens before attempting to log in
    if (reset) {
      this.$auth.reset({ resetInterceptor: false })
    }

    // Add client id to payload if defined
    if (this.options.clientId) {
      endpoint.data.client_id = this.options.clientId
    }

    // Add grant type to payload if defined
    if (this.options.grantType) {
      endpoint.data.grant_type = this.options.grantType
    }

    // Add scope to payload if defined
    if (this.options.scope) {
      endpoint.data.scope = this.options.scope
    }

    // Make login request
    const response = await this.$auth.request(
      endpoint,
      this.options.endpoints.login
    )

    // 2FA enabled
    if (
      (response.data.google2fa_enabled != null && response.data.google2fa_enabled == true) ||
      response.data.google2fa_disabled != null
    ) {
      return response
    }

    // Update tokens
    this.updateTokens(response)

    // Initialize request interceptor if not initialized
    if (!this.requestHandler.interceptor) {
      this.initializeRequestInterceptor()
    }

    // Fetch user if `autoFetch` is enabled
    if (this.options.user.autoFetch) {
      await this.fetchUser()
    }

    return response
  }

}

However, Laravel Sanctum appears to be using the cookie scheme and calling the login method from the local scheme? But when I add the local scheme's login function to a new custom scheme that includes the cookie functionality it doesn't send the CSRF request and everything else needed, what am I doing wrong?

My attempt at creating a Laravel Sanctum override scheme

import { CookieScheme } from '~auth/runtime'

export default class CustomCookieScheme extends CookieScheme {
  async login(endpoint) {
    // Ditch any leftover local tokens before attempting to log in
    this.$auth.reset()

    // Make CSRF request if required
    if (this.options.endpoints.csrf) {
      await this.$auth.request(this.options.endpoints.csrf, {
        maxRedirects: 0
      })
    }

    console.log('custom cookie scheme running')

    // Log in
    if (!this.options.endpoints.login) {
      return
    }

    // Add client id to payload if defined
    if (this.options.clientId) {
      endpoint.data.client_id = this.options.clientId
    }

    // Add grant type to payload if defined
    if (this.options.grantType) {
      endpoint.data.grant_type = this.options.grantType
    }

    // Add scope to payload if defined
    if (this.options.scope) {
      endpoint.data.scope = this.options.scope
    }

    // Make login request
    const response = await this.$auth.request(
      endpoint,
      this.options.endpoints.login
    )

    // Update tokens
    this.updateTokens(response)

    // Initialize request interceptor if not initialized
    if (!this.requestHandler.interceptor) {
      this.initializeRequestInterceptor()
    }

    // Fetch user if `autoFetch` is enabled
    if (this.options.user.autoFetch) {
      await this.fetchUser()
    }

    return response
  }
}