0.1.2 • Published 7 months ago

@ouim/simple-logto v0.1.2

Weekly downloads
-
License
MIT
Repository
github
Last release
7 months ago

@ouim/simple-logto

A simpler way to use @logto/react with prebuilt UI components and hooks for fast authentication setup in React apps.


Features

Frontend Components & Hooks

  • AuthProvider: Easy context provider for Logto authentication
  • UserCenter: Prebuilt user dropdown/avatar for your navbar
  • CallbackPage: Handles OAuth callback and popup flows
  • SignInPage: Standalone sign-in page component
  • useAuth: React hook for accessing user and auth actions
  • Custom navigation: Integrates with React Router, Next.js, etc.
  • Popup sign-in: Support for popup-based authentication
  • Guest mode: Built-in guest user support with fingerprinting

Backend Authentication

  • JWT Verification: Manual JWT verification with JWKS caching
  • Express.js Middleware: Ready-to-use Express middleware
  • Next.js Support: API routes and middleware helpers
  • Scope-based Authorization: Built-in scope validation
  • Multiple Token Sources: Supports cookies and Authorization headers
  • TypeScript Support: Full TypeScript definitions

Bundler Configuration

  • Vite: Pre-configured Vite settings
  • Webpack: Webpack configuration helpers
  • Next.js: Next.js bundler configuration

Installation

npm install @ouim/simple-logto

Quick Start

Frontend Setup

Frontend Setup

1. AuthProvider

Wrap your app with AuthProvider and pass your Logto config:

import { AuthProvider } from '@ouim/simple-logto'

const config = {
  endpoint: 'https://your-logto-endpoint.com',
  appId: 'your-app-id',
}

function App() {
  return (
    <AuthProvider
      config={config}
      callbackUrl="http://localhost:3000/callback"
      enablePopupSignIn={true} // Enable popup-based sign-in
      // Optionally: customNavigate for SPA routing
      // customNavigate={(url, options) => { ... }}
    >
      <YourApp />
    </AuthProvider>
  )
}

2. UserCenter Component

Drop the UserCenter component into your navbar for a ready-to-use user menu:

import { UserCenter } from '@ouim/simple-logto'

function Navbar() {
  return (
    <nav className="flex items-center justify-between h-16 px-4 border-b">
      <div className="font-bold">MyApp</div>
      <UserCenter />
    </nav>
  )
}
  • Shows avatar, name, and sign out when authenticated.
  • Shows sign in button when not authenticated.
  • Accepts optional props:
    • className
    • signoutCallbackUrl (defaults to /)
    • globalSignOut (defaults to true)
    • additionalPages - array of { link: string; text: string; icon?: ReactNode }

Example adding custom pages:

<UserCenter additionalPages={[{ link: '/settings', text: 'Go to your settings' }]} />

3. CallbackPage

Create a route (e.g. /callback) and render CallbackPage to handle OAuth redirects:

import { CallbackPage } from '@ouim/simple-logto'

export default function Callback() {
  return <CallbackPage />
}
  • Handles both normal and popup sign-in flows.
  • Optional props:
    • onSuccess, onError, loadingComponent, successComponent

4. SignInPage (Optional)

For a standalone sign-in page:

import { SignInPage } from '@ouim/simple-logto'

export default function SignIn() {
  return <SignInPage />
}

5. useAuth Hook

Access the current user and authentication actions anywhere in your app:

import { useAuth } from '@ouim/simple-logto'

function Dashboard() {
  const { user, isLoadingUser, signIn, signOut } = useAuth()

  if (isLoadingUser) return <div>Loading...</div>
  if (!user) return <button onClick={() => signIn()}>Sign in</button>

  return (
    <div>
      <p>Welcome, {user.name}!</p>
      <button onClick={() => signOut()}>Sign out</button>
    </div>
  )
}

5. useAuth Hook

Access the current user and authentication actions anywhere in your app:

import { useAuth } from '@ouim/simple-logto'

function Dashboard() {
  const { user, isLoadingUser, signIn, signOut, refreshAuth } = useAuth()

  if (isLoadingUser) return <div>Loading...</div>
  if (!user) return <button onClick={() => signIn()}>Sign in</button>

  return (
    <div>
      <p>Welcome, {user.name}!</p>
      <button onClick={() => signOut()}>Sign out</button>
      <button onClick={refreshAuth}>Refresh Auth</button>
    </div>
  )
}
Route Protection Example
function ProtectedPage() {
  const { user } = useAuth({
    middleware: 'auth',
    redirectTo: '/login', // Redirect if not authenticated
  })

  if (!user) return null // or loading indicator
  return <div>Protected content</div>
}
Guest Mode Example
function MixedContent() {
  const { user } = useAuth({
    middleware: 'guest', // Allow guest users
  })

  return <div>{user ? <p>Welcome back, {user.name}!</p> : <p>You're browsing as a guest</p>}</div>
}

Backend Authentication

The library includes powerful backend authentication helpers for Node.js applications.

Installation

Backend features are included with the main package:

npm install @ouim/simple-logto

Express.js Middleware

import { createExpressAuthMiddleware } from '@ouim/simple-logto/backend'

const authMiddleware = createExpressAuthMiddleware({
  logtoUrl: 'https://your-logto-domain.com',
  audience: 'your-api-resource-identifier',
  cookieName: 'logto_authtoken', // optional, defaults to 'logto_authtoken'
  requiredScope: 'some_scope', // optional
  allowGuest: true, // optional, enables guest mode
})

// Use in your Express routes
app.get('/protected', authMiddleware, (req, res) => {
  res.json({
    message: 'Hello authenticated user!',
    userId: req.auth.userId,
    isAuthenticated: req.auth.isAuthenticated,
    isGuest: req.auth.isGuest,
  })
})

Next.js API Routes

// app/api/protected/route.js
import { verifyNextAuth } from '@ouim/simple-logto/backend'

export async function GET(request) {
  const authResult = await verifyNextAuth(request, {
    logtoUrl: 'https://your-logto-domain.com',
    audience: 'your-api-resource-identifier',
    cookieName: 'logto_authtoken', // optional
    requiredScope: 'some_scope', // optional
    allowGuest: true, // optional
  })

  if (!authResult.success) {
    return Response.json({ error: authResult.error }, { status: 401 })
  }

  return Response.json({
    message: 'Hello authenticated user!',
    userId: authResult.auth.userId,
    payload: authResult.auth.payload,
  })
}

Next.js Middleware

// middleware.js
import { verifyNextAuth } from '@ouim/simple-logto/backend'
import { NextResponse } from 'next/server'

export async function middleware(request) {
  if (request.nextUrl.pathname.startsWith('/api/protected')) {
    const authResult = await verifyNextAuth(request, {
      logtoUrl: process.env.LOGTO_URL,
      audience: process.env.LOGTO_AUDIENCE,
    })

    if (!authResult.success) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    // Add auth info to headers for the API route
    const response = NextResponse.next()
    response.headers.set('x-user-id', authResult.auth.userId)
    return response
  }
}

export const config = {
  matcher: '/api/protected/:path*',
}

Generic Usage

import { verifyAuth } from '@ouim/simple-logto/backend'

// Verify with token string
try {
  const auth = await verifyAuth('your-jwt-token', {
    logtoUrl: 'https://your-logto-domain.com',
    audience: 'your-api-resource-identifier',
  })

  console.log('User ID:', auth.userId)
} catch (error) {
  console.error('Auth failed:', error.message)
}

// Verify with request object
try {
  const auth = await verifyAuth(requestObject, {
    logtoUrl: 'https://your-logto-domain.com',
    audience: 'your-api-resource-identifier',
  })
} catch (error) {
  console.error('Auth failed:', error.message)
}

Backend Configuration Options

  • logtoUrl: Your Logto server URL (required)
  • audience: Your API resource identifier (required)
  • cookieName: Custom cookie name (optional, defaults to 'logto_authtoken')
  • requiredScope: Required scope for access (optional)
  • allowGuest: Enable guest mode with fingerprinting (optional)

Auth Context

When authentication is successful, you'll get an AuthContext object:

interface AuthContext {
  userId: string | null // User ID from token (null for guests)
  isAuthenticated: boolean // true for authenticated users
  isGuest: boolean // true for guest users
  payload: AuthPayload | null // Full JWT payload (null for guests)
  guestId?: string // Guest fingerprint ID (when allowGuest is true)
}

Bundler Configuration

The library provides pre-configured bundler settings to resolve common issues with the jose library and other dependencies.

Vite

// vite.config.js
import { viteConfig } from '@ouim/simple-logto'

export default {
  ...viteConfig,
  // your other config
}

Webpack

// webpack.config.js
import { webpackConfig } from '@ouim/simple-logto'

module.exports = {
  ...webpackConfig,
  // your other config
}

Next.js

// next.config.js
import { nextjsConfig } from '@ouim/simple-logto'

module.exports = {
  ...nextjsConfig,
  // your other config
}

Custom Configuration

import { getBundlerConfig } from '@ouim/simple-logto'

// Get configuration for specific bundler
const config = getBundlerConfig('vite') // 'vite' | 'webpack' | 'nextjs'

Utilities

The library also exports several utility functions:

import { cookieUtils, jwtCookieUtils } from '@ouim/simple-logto'

// Cookie utilities
cookieUtils.set('key', 'value')
cookieUtils.get('key')
cookieUtils.remove('key')

// JWT-specific cookie utilities
jwtCookieUtils.setToken('jwt-token')
jwtCookieUtils.getToken()
jwtCookieUtils.removeToken()

TypeScript Support

The library is written in TypeScript and provides comprehensive type definitions:

import type { LogtoUser, AuthOptions, AuthMiddleware, CallbackPageProps, NavigationOptions, AdditionalPage } from '@ouim/simple-logto'

// Backend types
import type { AuthContext, AuthPayload, VerifyAuthOptions } from '@ouim/simple-logto/backend'