@logickernel/bridge
v0.15.7
Published
Framework-agnostic micro-frontend authentication library for AuthJS/NextAuth JWT tokens
Maintainers
Readme
@logickernel/bridge
Framework-agnostic micro-frontend authentication library for AuthJS/NextAuth JWT tokens with built-in Next.js components.
Installation
npm install @logickernel/bridgeQuick Start (Next.js)
1. Environment Variables
Add these to the .env file of your application:
AUTH_SECRET=your-nextauth-secret # Required: Same secret used by your kernel/auth server
AUTH_URL=http://localhost:3000 # Required: Base URL of your kernel/auth server
BASE_URL=http://localhost:7001 # Optional: Your facade URL for user-facing redirects2. Configure Next.js
In your next.config.ts, add the bridge package to transpilePackages:
import type { NextConfig } from "next"
const nextConfig: NextConfig = {
transpilePackages: ["@logickernel/bridge"],
// ... other config
}
export default nextConfigUse webpack instead of Turbopack (the default) in your package.json scripts:
{
"scripts": {
"dev": "next dev --webpack",
"build": "next build --webpack"
}
}3. Configure Tailwind CSS
Add the @source directive to your src/app/globals.css to ensure Tailwind scans classes from this package:
@import "tailwindcss";
/* ... other imports ... */
@source "../../node_modules/@logickernel/bridge/dist/**/*.{js,cjs}";Note: If using a local file:../bridge dependency, use @source "../../../bridge/dist/**/*.{js,cjs}"; instead. Restart your dev server after adding this directive.
4. Use the Layout Component
Create a wrapper component to establish the client/server boundary:
"use client"
/**
* Client boundary wrapper for AppLayout.
*
* This wrapper is required because "use client" directives are not preserved
* in bundled library code. Next.js needs this directive in your source code
* to properly handle the client/server boundary.
*/
import { AppLayout } from "@logickernel/bridge/next/components"
export function AppLayoutWrapper({
children,
organizationId,
apiBaseUrl,
}: {
children: React.ReactNode
organizationId?: string
apiBaseUrl?: string
}) {
return (
<AppLayout
organizationId={organizationId}
apiBaseUrl={apiBaseUrl}
>
{children}
</AppLayout>
)
}Use in your layout:
import { redirect } from "next/navigation"
import { auth } from "@/lib/next-auth" // or your auth setup
import { AppLayoutWrapper } from "@/components/app-layout-wrapper"
export default async function Layout({
children,
}: {
children: React.ReactNode
}) {
const session = await auth()
if (!session?.user) {
redirect("/core/auth/signin?callbackUrl=/core/app")
}
return (
<AppLayoutWrapper>
{children}
</AppLayoutWrapper>
)
}The layout automatically fetches user information from the navigation API endpoint.
5. Navigation API Endpoint
The layout automatically loads navigation items from /core/api/navigation/[organization_id].
Required Endpoint: GET /core/api/navigation/[organization_id]
Response Payload:
{
items: NavigationItem[]
organizationId: string
organizations: NavigationOrganization[]
user: {
id: string
name: string | null
email: string
image: string | null
}
}
interface NavigationItem {
title: string
url?: string // If missing, item is treated as a section label
icon?: string // Lucide icon name (e.g., "LayoutDashboard", "Users")
isActive?: boolean // Whether the item should be highlighted
items?: { // Sub-items for collapsible navigation
title: string
url: string
}[]
}
interface NavigationOrganization {
id: string
name: string
logo?: string // Lucide icon name for the organization logo
plan?: string // Optional plan/badge text
}The endpoint should be protected and only return data the authenticated user has access to. The {organizationId} placeholder in item URLs is automatically replaced with the current organization ID.
Features
- Built-in sidebar navigation with collapsible sections
- Organization switcher
- User menu with profile and sign-out
- Responsive design (mobile and desktop)
- Automatic navigation loading from API
- Consistent UI across microfrontends
Next.js Utilities
Server Components / Pages
import { getSession } from "@logickernel/bridge/next"
import { redirect } from "next/navigation"
export default async function DashboardPage() {
const session = await getSession()
if (!session) {
redirect("/core/auth/signin")
}
return <div>Welcome, {session.user.email}!</div>
}Role-Based Page Protection
import { checkPageAuth } from "@logickernel/bridge/next"
import { redirect, notFound } from "next/navigation"
export default async function AdminPage({
params,
}: {
params: Promise<{ organization_id: string }>
}) {
const { organization_id } = await params
const auth = await checkPageAuth({
requiredRoles: ["organization.owner", "organization.editor"],
organizationId: organization_id,
})
if (!auth.authenticated) {
redirect(auth.redirectUrl)
}
if (!auth.hasRequiredRole) {
notFound()
}
return <div>Admin Panel for {auth.session.user.email}</div>
}API Routes
import { withAuth } from "@logickernel/bridge/next"
import { NextResponse } from "next/server"
// Any authenticated user
export const GET = withAuth(async (request, { session }) => {
return NextResponse.json({
userId: session.user.id,
email: session.user.email,
})
})
// With role requirements
export const DELETE = withAuth(
async (request, { session }) => {
// Only owners can delete
return NextResponse.json({ deleted: true })
},
{
requiredRoles: ["organization.owner"],
organizationId: "org_id", // Extract from route params
}
)Middleware / Proxy
// middleware.ts or proxy.ts
import { createProxyHandler, type ProxyOptions } from "@logickernel/bridge/next"
const config: ProxyOptions = {
basePath: "/app",
routes: {
"/dashboard": [], // Any authenticated user (relative to basePath)
"/settings": [],
"/[organization_id]/admin": ["organization.owner"], // Dynamic route with role requirement
},
}
export const proxy = createProxyHandler(config)
// Static config for Next.js middleware
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico|public).*)"],
}Import Paths
// Core utilities (framework-agnostic)
import { decodeSessionToken, fetchUserRoles } from "@logickernel/bridge"
// Next.js utilities (server components, API routes, middleware)
import { getSession, withAuth, checkPageAuth } from "@logickernel/bridge/next"
// Layout components (client components)
import { AppLayout, type User } from "@logickernel/bridge/next/components"API Reference
Core Exports (@logickernel/bridge)
| Export | Description |
|--------|-------------|
| decodeSessionToken(token, secret, isSecure) | Decode and validate a JWT session token |
| extractSessionCookie(cookies) | Extract session cookie from a cookies object |
| fetchUserRoles(options) | Fetch user roles from the kernel API |
| hasAnyRole(userRoles, requiredRoles) | Check if user has at least one required role |
| hasAllRoles(userRoles, requiredRoles) | Check if user has all required roles |
| hasRole(userRoles, role) | Check if user has a specific role |
Next.js Exports (@logickernel/bridge/next)
| Export | Description |
|--------|-------------|
| getSession() | Get the current session from cookies |
| getSessionToken() | Get the raw session token value |
| getUserRoles(orgId) | Get user roles in an organization |
| withAuth(handler, options?) | Wrap an API route with authentication |
| checkPageAuth(options?) | Check authentication for a page |
| requireAuth() | Require authentication (throws if not authenticated) |
| hasRequiredRole(orgId, roles) | Check if user has required roles |
| createProxyHandler(options) | Create a middleware/proxy handler |
Layout Components (@logickernel/bridge/next/components)
| Export | Description |
|--------|-------------|
| AppLayout | Main layout component with sidebar navigation (wrap in a local component with "use client" for server components) |
| useNavigation | Hook to fetch navigation items from API |
| getIconComponent | Utility to get icon component from icon name |
AppLayout Props:
interface AppLayoutProps {
user?: User // Optional: Auto-fetched if not provided
organizationId?: string // Optional: Current organization ID
apiBaseUrl?: string // Optional: Defaults to "/core/api"
children: React.ReactNode
}TypeScript Types
// Core types
import type {
Session,
SessionUser,
DecodeResult,
} from "@logickernel/bridge"
// Next.js types
import type {
ProxyOptions,
AuthContext,
AuthenticatedHandler,
PageAuthOptions,
PageAuthResult,
} from "@logickernel/bridge/next"
// Component types
import type {
User,
NavigationItem,
NavigationOrganization,
} from "@logickernel/bridge/next/components"Architecture
bridge/
├── src/
│ ├── index.ts # Core exports (framework-agnostic)
│ ├── jwt.ts # JWT decoding utilities
│ ├── roles.ts # Role checking utilities
│ └── next/
│ ├── index.ts # Next.js adapter exports
│ ├── session.ts # Session utilities
│ ├── api.ts # API route utilities
│ ├── page.ts # Page utilities
│ ├── proxy.ts # Middleware/proxy utilities
│ └── components/
│ ├── app-layout.tsx # Main layout component
│ ├── app-sidebar.tsx # Sidebar component
│ ├── nav-main.tsx # Navigation component
│ ├── nav-user.tsx # User menu component
│ ├── team-switcher.tsx # Organization switcher
│ ├── use-navigation.ts # Navigation hook
│ └── ui/ # Internal UI components (shadcn)Development
# Install dependencies
npm install
# Build the library
npm run build
# Watch mode for development
npm run dev
# Type checking
npm run typecheck
# Clean build artifacts
npm run cleanLicense
MIT
