Skip to content

work-mate/nuxt-auth-module

Repository files navigation

Auth module for Nuxt 3 server apps

NPM npm GitHub last commit


Auth module for Nuxt 3 apps.

Featured Auth Providers

Provider Provider Key Status
Local local âś…
Google google âś…
Github github âś…
Facebook facebook 🚧
LinkedIn linkedin 🚧

Local Auth Features

Feature Status
Login âś…
Logout âś…
User âś…
Refresh Token âś…

Installation

Package Manager

# using npm
npm install --save @workmate/nuxt-auth

# using yarn
yarn add @workmate/nuxt-auth

Setup

Add to modules

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    "@workmate/nuxt-auth"
  ],
  ...
});

Configure Auth

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@workmate/nuxt-auth"],
  auth: {
    providers: {
      local: {
        endpoints: {
          signIn: {
            path: "/signin",
            method: "POST",
            tokenKey: "token",
            body: {
              principal: "username",
              password: "password",
            },
          },
        },
      },

      github: {
        CLIENT_ID: process.env.GITHUB_CLIENT_ID || "",
        CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET || "",
        HASHING_SECRET: process.env.HASHING_SECRET || "secret",
        SCOPES: "user repo",
      },

      google: {
        CLIENT_ID: process.env.GOOGLE_CLIENT_ID || "",
        CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET || "",
        HASHING_SECRET: process.env.HASHING_SECRET || "secret",
        SCOPES:
          "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
      },
    },
    global: false,
    redirects: {
      redirectIfNotLoggedIn: "/login",
      redirectIfLoggedIn: "/",
    },
    apiClient: {
      baseURL: "",
    },
    defaultProvider: "local",
    token: {
      type: "Bearer",
      maxAge: 1000 * 60 * 60 * 24 * 30,
      cookiesNames: {
        accessToken: "auth:token",
        refreshToken: "auth:refreshToken",
        authProvider: "auth:provider",
        tokenType: "auth:tokenType",
      },
    },
  },
});

Full List of Module Options

interface ModuleOptions {
  providers: ModuleProvidersOptions;
  global: boolean;
  defaultProvider?: string;
  redirects: {
    redirectIfNotLoggedIn?: string;
    redirectIfLoggedIn?: string;
  };
  apiClient: {
    baseURL: string;
  };
  token: {
    type: string;
    maxAge: number;
    cookiesNames: {
      accessToken: string;
      refreshToken: string;
      authProvider: string;
    };
  };
}

type ModuleProvidersOptions = {
  local?: LocalAuthInitializerOptions;
  github?: GithubAuthInitializerOptions;
  google?: GoogleAuthInitializerOptions;
};

type HttpMethod =
  | "GET"
  | "HEAD"
  | "PATCH"
  | "POST"
  | "PUT"
  | "DELETE"
  | "CONNECT"
  | "OPTIONS"
  | "TRACE";

type LocalAuthInitializerOptions = {
  endpoints?: {
    signIn?: {
      path?: string;
      method?: HttpMethod;
      tokenKey?: string;
      refreshTokenKey?: string;
      body?: {
        principal?: string;
        password?: string;
      };
    };
    signOut?: { path: string; method: HttpMethod } | false;
    signUp?: { path?: string; method?: HttpMethod } | false;
    user?: { path: string; userKey: string } | false;
    refreshToken?:
      | {
          path: string;
          method: HttpMethod;
          tokenKey: string;
          refreshTokenKey: string;
          body: {
            token: string;
            refreshToken: string;
          };
        }
      | false;
  };
};

type GithubAuthInitializerOptions = {
  CLIENT_ID: string;
  CLIENT_SECRET: string;
  HASHING_SECRET: string;
  SCOPES?: string;
};

type GoogleAuthInitializerOptions = {
  CLIENT_ID: string;
  CLIENT_SECRET: string;
  HASHING_SECRET: string;
  SCOPES?: string;
}

Usage

While using the social auth (google, github)

Add the callback URL to the auth provider configuration. For example: <base url>/api/auth/callback/<provider> for google it would be <base url>/api/auth/callback/google.

composables

const {
  loggedIn,
  user,
  token,
  refreshToken,
  login,
  logout,
  refreshUser,
  refreshTokens,
} = useAuth();

// state is of type AuthState
type AuthPlugin = {
  loggedIn: ComputedRef<boolean>;
  user: ComputedRef<any | null | undefined>;
  token: ComputedRef<string | undefined>;
  refreshToken: ComputedRef<string | undefined>;
  tokenType: ComputedRef<string | undefined>;
  provider: ComputedRef<string | undefined>;
  login: (
    provider: string | SupportedAuthProvider,
    data?: Record<string, string>,
    redirectTo?: string,
  ) => Promise<
    | {
        tokens: AccessTokens;
      }
    | {
        message: string;
      }
  >;
  logout: (redirectTo?: string) => Promise<unknown>;
  refreshUser: () => Promise<void>;
  refreshTokens: () => Promise<void>;
};

To use useFetch with the authorization header, use useAuthFetch, and instead of using $fetch use $authFetch

useAuthFetch("/api/auth/melting", options);

// instead of $fetch,
$fetch("/api/auth/melting", options);

// use,
const { $authFetch } = useNuxtApp();
$authFetch("/api/auth/melting", options);

to change the base URI of the authFetch client, update the nuxt.config.ts

// nuxt.config.ts
export default defineNuxtConfig({
  auth: {
    ...
    apiClient: {
      baseURL: "http://localhost:8080/v1",
    },
    ...
  },
})

Logging in

const { login } = useAuth();

// to login
login("local", {
  principal,
  password,
});

// using github
login("github");

middlewares

Route middleware

To protect a page

// pages/index.vue
definePageMeta({
  middleware: "auth",
});

// or if adding it to a list of middlewares
definePageMeta({
  middleware: [..., "auth", ...],
});

To make sure a page is only accessible if you are not logged in. Eg. a login page

// pages/login.vue
definePageMeta({
  middleware: "auth-guest",
});

// or if adding it to a list of middlewares
definePageMeta({
  middleware: [..., "auth-guest", ...],
});

Global middleware

For a global middleware, set the the auth.global to true in the nuxt.config.ts file

export default defineNuxtConfig({
  ...
  auth: {
    global: true,
    ...
  },
})

To prevent a page from being protected from auth, set the auth meta to false

// pages/index.vue
definePageMeta({
  auth: false,
});

Example of nuxt.config.ts

const BACKEND_URL = "http://localhost:8080/api/v1";
export default defineNuxtConfig({
  modules: ["@workmate/nuxt-auth"],
  auth: {
    global: true,
    redirects: {
      redirectIfLoggedIn: "/protected",
    },
    apiClient: {
      baseURL: BACKEND_URL,
    },
    providers: {
      local: {
        endpoints: {
          user: {
            path: BACKEND_URL + "/api/auth/user",
            userKey: "user",
          },
          signIn: {
            path: BACKEND_URL + "/api/auth/login/password",
            body: {
              principal: "email_address",
              password: "password",
            },
            tokenKey: "token",
            refreshTokenKey: "refresh_token",
          },
          refreshToken: {
            path: BACKEND_URL + "/api/auth/refresh",
            method: "POST",
            tokenKey: "token",
            refreshTokenKey: "refresh_token",
            body: {
              token: "token",
              refreshToken: "refresh_token",
            },
          },
        },
      },

      github: {
        CLIENT_ID: process.env.GITHUB_CLIENT_ID || "",
        CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET || "",
        HASHING_SECRET: process.env.HASHING_SECRET || "secret",
        SCOPES: "user repo",
      },
    },
  },
});