npm package: @lantern-ai/auth-core-utility
Description: Shared Auth0 utilities for React and Express applications
Latest version: 1.0.0

# Auth Core Utility

A shared authentication package that provides Auth0 integration utilities for both React and Express applications.

## Features and Functionalities

This utility is designed to provide a seamless and secure authentication experience by offering a unified set of tools for both frontend (React) and backend (Express) applications.

### For React (Client-Side)

The React utilities are built on top of the official `auth0-react` SDK, providing a simplified and integrated experience.

-   **`AuthProvider`**: A wrapper component that provides the core authentication context to your entire React application. It handles the initialization of the Auth0 client and manages the authentication state.

-   **`useAuth()` Hook**: The primary hook for accessing authentication state and user information within your components. It returns:
    -   `user`: An object containing the profile information of the logged-in user.
    -   `isAuthenticated`: A boolean flag indicating if the user is authenticated.
    -   `isLoading`: A boolean that is `true` while the SDK is initializing or a login/logout is in progress.
    -   `loginWithRedirect()`: A function to redirect the user to the Auth0 login page.
    -   `logout()`: A function to log the user out.
    -   `getAccessTokenSilently()`: A function to silently retrieve an access token for making authenticated API calls.

-   **`useAuthFetch()` Hook**: A convenience hook that returns an instance of `fetch` pre-configured with the user's access token. This simplifies making authenticated requests to your backend API.

-   **`LoginButton` & `LogoutButton`**: Pre-built and styled UI components that trigger the login and logout flows, allowing for rapid implementation of authentication UI.

### For Express (Server-Side)

The Express middleware helps you protect your API endpoints by validating JSON Web Tokens (JWTs) issued by Auth0.

-   **`createAuthMiddleware(options)`**: A factory function that creates the main authentication middleware. It configures the JWT validation based on your Auth0 domain and API audience, ensuring that incoming tokens are valid and trusted.

-   **`requireAuth`**: A middleware that should be placed after `createAuthMiddleware`. It checks if a valid user profile has been attached to the request (`req.auth`), effectively protecting the route from unauthenticated access.

-   **`requireRole(role: string | string[])`**: A middleware for implementing Role-Based Access Control (RBAC). It ensures that the authenticated user has one or more specified roles before allowing access to a particular endpoint.

## Installation

Install the package in your project:

```bash
npm install @lantern/auth-core-utility
# or
yarn add @lantern/auth-core-utility
```

## Usage

### React Setup

Wrap your app with `AuthProvider`. To handle redirects after login, you can provide an `onRedirectCallback` function. This is useful for returning users to the page they were on before authenticating.

```tsx
import { AuthProvider } from '@lantern/auth-core-utility';

function App() {
  const onRedirectCallback = (appState?: unknown) => {
    const state = appState as { returnTo?: string } | undefined;
    const target = (state && state.returnTo) || window.location.pathname;
    window.history.replaceState({}, document.title, target);
  };

  return (
    <AuthProvider 
      config={{
        domain: 'your-auth0-domain',
        clientId: 'your-auth0-client-id',
        audience: 'your-auth0-audience'
      }}
      onRedirectCallback={onRedirectCallback}
    >
      <YourApp />
    </AuthProvider>
  );
}
```

Use authentication in components:

```tsx
import { useAuth, LoginButton, LogoutButton } from '@lantern/auth-core-utility';

function Profile() {
  const { user, isAuthenticated, isLoading } = useAuth();

  if (isLoading) return <div>Loading...</div>;
  if (!isAuthenticated) return <LoginButton />;

  return (
    <div>
      <h2>Welcome {user?.name}</h2>
      <LogoutButton />
    </div>
  );
}
```

### Express Setup

Protect your API routes:

```typescript
import { createAuthMiddleware, requireAuth, requireRole } from '@lantern/auth-core-utility';

const app = express();

// Setup auth middleware
const auth = createAuthMiddleware({
  auth0Domain: 'your-auth0-domain',
  audience: 'your-api-identifier'
});

// Protect routes
app.get('/api/protected', auth, requireAuth, (req, res) => {
  res.json({ message: 'Protected data' });
});

// Role-based protection
app.get('/api/admin', auth, requireRole('admin'), (req, res) => {
  res.json({ message: 'Admin only data' });
});
```

## API Reference

### React Components & Hooks

- `AuthProvider` - Main provider component
- `useAuth` - Hook for authentication state
- `LoginButton` - Pre-built login button
- `LogoutButton` - Pre-built logout button
- `ProtectedRoute` - Route guard component

### Express Middleware

- `createAuthMiddleware` - Creates JWT validation middleware
- `requireAuth` - Ensures request is authenticated
- `requireRole` - Validates user has required role

## Configuration

### AuthProvider Props

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| config.domain | string | Yes | Auth0 domain |
| config.clientId | string | Yes | Auth0 client ID |
| config.audience | string | No | API identifier |
| config.redirectUri | string | No | Redirect URL after login |

## Development

```bash
# Install dependencies
yarn install

# Build package
yarn build

# Run tests
yarn test
```

## Publishing the Package

### 1. Update package.json

```json
{
  "name": "@lantern/auth-core-utility",
  "version": "1.0.0",
  "private": false,
  "main": "dist/index.js",
  "module": "dist/index.esm.js",
  "types": "dist/index.d.ts",
  "files": [
    "dist"
  ],
  "publishConfig": {
    "access": "public"
  }
}
```

### 2. Build the Package
```bash
# Install dependencies
yarn install

# Build the package
yarn build
```

### 3. Publish to NPM Registry
```bash
# Login to NPM
npm login

# Publish package
npm publish --access public
```

## Using the Package

### In a React Project

1. Install the package:
```bash
# Using npm
npm install @lantern/auth-core-utility @auth0/auth0-react react-router-dom

# Using yarn
yarn add @lantern/auth-core-utility @auth0/auth0-react react-router-dom
```

2. Wrap your app with AuthProvider:
```tsx
// src/App.tsx or similar
import { AuthProvider } from '@lantern/auth-core-utility';

function App() {
  const onRedirectCallback = (appState?: unknown) => {
    const state = appState as { returnTo?: string } | undefined;
    const target = (state && state.returnTo) || window.location.pathname;
    window.history.replaceState({}, document.title, target);
  };

  return (
    <AuthProvider 
      config={{
        domain: 'your-auth0-domain',
        clientId: 'your-auth0-client-id',
      }}
      onRedirectCallback={onRedirectCallback}
    >
      <YourApp />
    </AuthProvider>
  );
}
```

3. Use authentication in components:
```tsx
// src/components/Profile.tsx
import { useAuth, LoginButton } from '@lantern/auth-core-utility';

function Profile() {
  const { user, isAuthenticated } = useAuth();
  
  if (!isAuthenticated) {
    return <LoginButton />;
  }
  
  return <div>Welcome, {user?.name}!</div>;
}
```

### In an Express Backend

1. Install the package:
```bash
# Using npm
npm install @lantern/auth-core-utility express-jwt jwks-rsa

# Using yarn
yarn add @lantern/auth-core-utility express-jwt jwks-rsa
```

2. Use middleware:
```typescript
// src/server.ts
import express from 'express';
import { createAuthMiddleware, requireAuth } from '@lantern/auth-core-utility';

const app = express();

const auth = createAuthMiddleware({
  auth0Domain: 'your-auth0-domain',
  audience: 'your-api-identifier'
});

app.get('/api/protected', 
  auth,              // Validate JWT
  requireAuth,       // Check authentication
  (req, res) => {
    res.json({ message: 'Protected route' });
  }
);
```

## Local Development

If you're developing this package locally in a monorepo:

1. Link the package:
```bash
# From the package directory
yarn link

# From your project directory
yarn link @lantern/auth-core-utility
```

2. Watch for changes:
```bash
# From the package directory
yarn watch
```

## Local Development with a Linked Package

When using this package in another project locally via `npm link` or `yarn link`, you might encounter issues, especially with applications created with Create React App. This is often due to two main problems:

1.  **Multiple instances of React:** The linked package might resolve its own copy of React, while your main application uses another. This leads to the "Invalid hook call" runtime error.
2.  **Transpilation:** The source code of the linked package needs to be transpiled by your main application's build process.

### Linking the Package

First, build and link the `@lantern/auth-core-utility` package:

```bash
# In the auth-core-utility directory
npm run build
npm link
```

Then, in your main project, link to the utility:

```bash
# In your main project's directory
npm link @lantern/auth-core-utility
```

### Configuration for Create React App (with Craco)

If your project uses [Craco](https://craco.js.org/) to override the Create React App configuration, you can solve the local linking issues by modifying your `craco.config.js`.

Add the following configuration to your `craco.config.js` file. This ensures that:
- Only one copy of `react` and `react-dom` is used.
- The build system can import files from outside the `src` directory.
- The `babel-loader` transpiles the linked utility's source code.

```javascript
// craco.config.js
const path = require('path');
const { getLoader, loaderByName } = require('@craco/craco');

module.exports = {
  webpack: {
    alias: {
      react: path.resolve(__dirname, 'node_modules/react'),
      'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
    },
    configure: (webpackConfig) => {
      // Allow importing from outside of src
      const scopePluginIndex = webpackConfig.resolve.plugins.findIndex(
        ({ constructor }) => constructor && constructor.name === 'ModuleScopePlugin'
      );
      if (scopePluginIndex > -1) {
        webpackConfig.resolve.plugins.splice(scopePluginIndex, 1);
      }

      // Find the babel-loader and add the linked package's src directory
      const { isFound, match } = getLoader(webpackConfig, loaderByName('babel-loader'));
      if (isFound) {
        const include = Array.isArray(match.loader.include)
          ? match.loader.include
          : [match.loader.include];
        
        // The path to the linked package, adjust if necessary
        const linkedPackagePath = path.resolve(__dirname, 'node_modules/@lantern/auth-core-utility');
        
        match.loader.include = include.concat([
          path.join(linkedPackagePath, 'src'),
        ]);
      }

      return webpackConfig;
    },
  },
};
```

After making these changes, restart your development server. Your application should now work correctly with the linked local package.

## Versioning

We use semantic versioning:
- MAJOR version for incompatible API changes
- MINOR version for new functionality in a backwards compatible manner
- PATCH version for backwards compatible bug fixes

```bash
# Bump version
npm version patch -m "Bump version to %s"
npm publish
```

## License

MIT