Auth-module: custom apollo strategy

Created on 10 Mar 2018  路  7Comments  路  Source: nuxt-community/auth-module

Hi! I'm trying to make my own strategy, but docs are limited and I'm doing my best to dig through source 馃槄 and now realized maybe asking here is best option...

Its a bit hacky, but here's my attempt:

  1. create a new class and implement the async methods login, fetchUser, etc.
  2. In a plugin, call app.$auth.registerStrategy('apollo', ApolloScheme);
  3. Inside of nuxt.config, make sure to set strategy to apollo

In my nuxt config:

plugins: [{ src: '~plugins/apollo-auth.js' }],
auth: {
  strategy: 'apollo',
},

inside apollo-auth.js:

import signIn from '~/apollo/queries/users/signIn';
import currentUser from '~/apollo/queries/users/user';


class ApolloScheme {
 ...
  async login(endpoint) {
    if (!this.options.endpoints.login) {
      return;
    }

    const {
      data: { signIn: { jwtToken } },
    } = await this.app.apolloProvider.clients.defaultClient.mutate({
      mutation: signIn,
      variables: {
        input: this.options.endpoints.login,
      },
    });

    if (this.options.tokenRequired) {
      const token = this.options.tokenType
        ? this.options.tokenType + ' ' + jwtToken
        : jwtToken;

      this.auth.setToken(this.name, token);
      this._setToken(token);
    }

    return this.fetchUser();
  }

  async fetchUser(endpoint) {
    // User endpoint is disabled.
    if (!this.options.endpoints.user) {
      this.auth.setUser({});
      return;
    }

    // Token is required but not available
    if (this.options.tokenRequired && !this.auth.getToken(this.name)) {
      return;
    }

    // Try to fetch user and then set
    const { data } = await this.app.apolloProvider.clients.defaultClient.query({
      query: currentUser,
    });

    if (!data.currentUser) {
      return;
    }

    this.auth.setUser(data);
  }

  async logout(endpoint) {
    if (!this.options.endpoints.logout) {
      return;
    }

    await this.auth
      .requestWith(this.name, endpoint, this.options.endpoints.logout)
      .catch(() => {});

    if (this.options.tokenRequired) {
      this._clearToken();
    }

    return this.auth.reset();
  }
}

export default ({ app }, inject) => {
  app.$auth.registerStrategy('apollo', ApolloScheme);
}

I already played with editing the source inside of the generated .nuxt folder, and I know the methods in the class generally works with apollo (yay!), but I wanted to do something that works with plugins, or monkey patches the auth module or could be npm installed. Thanks!

This question is available on Nuxt.js community (#c68)

Most helpful comment

You can try my apollo-schema.js

 import meQuery from "~/graphql/queries/me.gql";
import loginMutation from '~/graphql/mutations/login.gql'

export default class ApolloScheme {


  constructor(auth, options) {
    this.$auth = auth
    this.$apollo = auth.ctx.app.apolloProvider.defaultClient
    this.$apolloHelpers = auth.ctx.app.$apolloHelpers
    this._name = options._name
  }



  async login({ data, tokenKey = 'token', userKey = 'user' }) {
    return this.$apollo
      .mutate({
        mutation: loginMutation,
        variables: data,
      })
      .then(({ data }) => Promise.resolve(Object.values(data)[0]))
      .then(data => this.setUserToken(data.token))
  }

  setToken(tokenValue) {
    return this.$apolloHelpers.onLogin(tokenValue)
      .then(() => this.$auth.setToken(this._name, tokenValue))
  }

  setUser(user) {
    return this.$auth.setUser(user)
  }

  setUserToken(tokenValue) {
    return this.setToken(tokenValue).then(() => this.fetchUser())
  }
  check() {
    let status = !!this.$auth.getToken(this._name) && this.$auth.getToken(this._name) !== this._name
    return status;
  }
  fetchUser() {
    if (!this.check()) {
      return Promise.reject(false)
    }

    return this.$apollo.query({ query: meQuery })
      .then(({ data }) => Promise.resolve(Object.values(data)[0]))
      .then(data => this.setUser(data))
  }

  logout() {
    return this.$apolloHelpers.onLogout()
      .then(() => this.reset())
  }

  reset() {
    return this.setToken(this._name, null).then(() => this.setUser(null))
  }
}

All 7 comments

You're actually trying to make your own scheme, strategies are instance of schemes

plugin.js from .nuxt dir is generated after nuxt.config.js thanks to a template: it's not supposed to be edited. If nuxt.config.js properly configures an appolo strategy, plugin.js will register it.

Take a look at the provided example to understand how to configure auth module in nuxt.config.js

As for your appolo scheme, you indeed need to implement the mentioned methods.

I've implemented a custom scheme called api here: to understand what is needed, I suggest that you

  • clone this repo
  • make a diff between api-auth and dev branches

Closing this as we will probably rework scheme to allow users to create their own schemes through npm packages 馃槃

Please has apollo strategy now been implemented for auth-module.. I'm in very much need for currently ongoing SaaS app using graphQL. I can't go forward with nuxt without this. I need it for the auth module, please help so I can meet deadline

You can try my apollo-schema.js

 import meQuery from "~/graphql/queries/me.gql";
import loginMutation from '~/graphql/mutations/login.gql'

export default class ApolloScheme {


  constructor(auth, options) {
    this.$auth = auth
    this.$apollo = auth.ctx.app.apolloProvider.defaultClient
    this.$apolloHelpers = auth.ctx.app.$apolloHelpers
    this._name = options._name
  }



  async login({ data, tokenKey = 'token', userKey = 'user' }) {
    return this.$apollo
      .mutate({
        mutation: loginMutation,
        variables: data,
      })
      .then(({ data }) => Promise.resolve(Object.values(data)[0]))
      .then(data => this.setUserToken(data.token))
  }

  setToken(tokenValue) {
    return this.$apolloHelpers.onLogin(tokenValue)
      .then(() => this.$auth.setToken(this._name, tokenValue))
  }

  setUser(user) {
    return this.$auth.setUser(user)
  }

  setUserToken(tokenValue) {
    return this.setToken(tokenValue).then(() => this.fetchUser())
  }
  check() {
    let status = !!this.$auth.getToken(this._name) && this.$auth.getToken(this._name) !== this._name
    return status;
  }
  fetchUser() {
    if (!this.check()) {
      return Promise.reject(false)
    }

    return this.$apollo.query({ query: meQuery })
      .then(({ data }) => Promise.resolve(Object.values(data)[0]))
      .then(data => this.setUser(data))
  }

  logout() {
    return this.$apolloHelpers.onLogout()
      .then(() => this.reset())
  }

  reset() {
    return this.setToken(this._name, null).then(() => this.setUser(null))
  }
}

@canhkieu I am running in the same issue and try to use your codes to start, but my app start to error Class constructor ApolloScheme cannot be invoked without 'new', I think it's babel related, is there anything that I should add to the nuxt.config.js?

@PlusA2M Sample config for auth with apollo-scheme

 auth: {
    cookie: {
      prefix: 'auth',
    },
    localStorage: false,
    strategies: {
      local: false,

      apollo: {
         _scheme: '~/plugins/auth/apollo-schema.js',
         name: 'apollo',
         provider: 'apollo',
         token_type: 'Bearer',
         default: true,
      },
      ...

@canhkieu

Thanks for your help! Though I found that I need to use scheme property instead of _scheme property in the nuxt.config.js, don't know why yet but I'm using the @nuxtjs/auth-next module at the moment.

Was this page helpful?
0 / 5 - 0 ratings