Skip to content

Instantly share code, notes, and snippets.

@exonomyapp
Last active August 10, 2024 17:58
Show Gist options
  • Save exonomyapp/92bfd7cbe8563a5bbe480cc2d6361ee4 to your computer and use it in GitHub Desktop.
Save exonomyapp/92bfd7cbe8563a5bbe480cc2d6361ee4 to your computer and use it in GitHub Desktop.
Nuxt Layers to facilitate modular (optional, conditional) authentication providers

Multi-provider authentication in Nuxt.js is typically organized using layers. This layered approach allows for a clean separation of concerns, making the authentication process more modular, maintainable, and scalable. Here's how this layered structure is commonly organized:

1. Authentication Providers Layer

  • OAuth/OIDC Providers: This layer handles integration with various third-party authentication providers, such as Google, Facebook, GitHub, etc. Each provider is configured separately with its respective credentials and settings.
  • Custom Authentication Providers: In addition to third-party providers, this layer can also include custom authentication methods, like using a custom API for login or integrating with enterprise authentication systems.

2. Authentication Service Layer

  • Abstraction over Providers: This layer acts as an abstraction over the various authentication providers. It handles the common tasks such as redirecting users to the appropriate provider, managing tokens, and handling the callback logic.
  • State Management: This layer interacts with the application's state management (like Vuex) to store the authentication state, user information, and tokens. It ensures that the application knows whether the user is authenticated and which provider was used.

3. Middleware Layer

  • Route Guards: Middleware is used to protect routes by checking the user's authentication status. It ensures that users can only access certain routes if they are authenticated and, if needed, only if they authenticated through specific providers.
  • Provider-Based Logic: The middleware can also apply logic based on the authentication provider. For instance, you might have different permission checks depending on whether the user logged in via Google or a custom API.

4. UI Layer

  • Login UI: This layer handles the user interface for login, including showing the different authentication options available to the user. It provides buttons or links to initiate authentication with various providers.
  • User Information Display: After authentication, this layer displays user information, such as their profile picture and name, depending on the provider they used to authenticate.

5. API Communication Layer

  • Token Management: This layer manages the storage, refresh, and use of authentication tokens when making API calls. It ensures that tokens are correctly sent with API requests and handles token expiration and renewal.
  • API Integration: It also manages integration with backend APIs, ensuring that authenticated requests are properly routed and that responses are handled according to the application's logic.

Example of How These Layers Work Together

When a user clicks on a "Login with Google" button (UI Layer), the application uses the Authentication Service Layer to initiate the OAuth process with Google (Authentication Providers Layer). Once Google redirects back with a token, the Authentication Service Layer handles the token, updates the Vuex store (State Management Layer), and then redirects the user to a protected route (Middleware Layer). If the user makes an API request, the API Communication Layer ensures that the token is included in the request headers.

Benefits of Layered Organization

  • Modularity: Each part of the authentication process is handled in its own layer, making it easier to manage and modify.
  • Scalability: New authentication providers can be added without significantly affecting other parts of the system.
  • Maintainability: With clear separation of concerns, debugging and updating the authentication logic becomes easier.
  • Flexibility: Custom logic can be applied at different layers without affecting the core authentication process.

This layered approach is a common pattern in complex applications where multiple authentication methods need to be managed efficiently.

In Nuxt, while both layers and components are ways to organize and modularize code, they serve different purposes and are utilized in distinct ways. Here's how Nuxt Layers are used in the context of multi-provider authentication to illustrate their unique role compared to components:

Distinguishing Layers from Components

Components:

  • Purpose: Components are reusable building blocks of the UI. They encapsulate specific pieces of the user interface and logic, such as buttons, forms, or widgets.
  • Scope: Components are generally smaller in scope and are used within pages or other components. They handle UI and local state but don't manage large-scale application architecture or cross-cutting concerns.

Layers:

  • Purpose: Layers are higher-level organizational units that encapsulate complete functional or logical segments of an application. They can include multiple components, pages, middleware, and configurations.
  • Scope: Layers are broader in scope compared to components. They manage significant parts of application functionality or architecture, like authentication, routing, or data handling.

How Nuxt Layers Are Used in Multi-Provider Authentication

1. Core Authentication Layer

  • Role: This layer is responsible for the fundamental authentication logic and user session management. It provides a centralized place for managing authentication state, handling tokens, and protecting routes.
  • Contents:
    • Configuration: Core configuration for authentication settings.
    • Middleware: Middleware to protect routes and ensure users are authenticated.
    • Utilities: Functions and services that are used across different authentication providers.

Example Usage:

// core-auth-layer/nuxt.config.ts
export default defineNuxtConfig({
  // Core authentication settings
  runtimeConfig: {
    auth: {
      secret: process.env.AUTH_SECRET
    }
  },
  // Register global middleware
  hooks: {
    'pages:extend'(pages) {
      pages.push({
        name: 'auth',
        path: '/auth',
        file: '~/core-auth-layer/middleware/auth.ts'
      });
    }
  }
});

2. Provider-Specific Layers

  • Role: Each provider layer encapsulates the authentication logic specific to a particular provider. It manages the OAuth flow, API interactions, and provider-specific configurations.
  • Contents:
    • Configuration: OAuth credentials and provider-specific settings.
    • Pages: Custom pages for login and callback handling related to the provider.
    • Logic: Functions and services specific to interacting with the provider’s API.

Example Usage:

// provider-google-layer/nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    auth: {
      google: {
        clientId: process.env.GOOGLE_CLIENT_ID
      }
    }
  },
  // Provider-specific pages and logic
  hooks: {
    'pages:extend'(pages) {
      pages.push({
        name: 'auth-google',
        path: '/auth/google',
        file: '~/provider-google-layer/pages/auth/google.vue'
      });
    }
  }
});

Integration in the Main Nuxt Application

In the main Nuxt application, you integrate these layers:

  1. Include Layers: Import and configure layers in the nuxt.config.ts of the main application to ensure they are recognized and used.

  2. Manage Routing: Handle the routing and authentication flows by leveraging the middleware and configuration from the core authentication layer and each provider layer.

Example Integration:

// main-nuxt-app/nuxt.config.ts
export default defineNuxtConfig({
  // Include layers
  buildModules: [
    '~/core-auth-layer',
    '~/provider-google-layer',
    '~/provider-facebook-layer'
  ],
  hooks: {
    'pages:extend'(pages) {
      // Dynamically extend or configure pages as needed
    }
  }
});

Summary

Unique Role of Layers:

  • Separation of Concerns: Layers manage larger sections of application functionality, like authentication, and include multiple related components and configurations. They are more about organizing the application's structure and logic than individual UI elements.
  • Modularity: Each layer represents a self-contained unit of functionality that can be developed, tested, and maintained independently. This modularity is distinct from the role of individual components, which are generally more focused on specific UI elements or small pieces of functionality.

By using layers, you structure your application in a way that maintains clean separation between different aspects of authentication and ensures that each part of your application remains modular and manageable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment