Framework-agnostic micro-frontend authentication library for AuthJS/NextAuth JWT tokens
npm install @logickernel/bridgeFramework-agnostic micro-frontend authentication library for AuthJS/NextAuth JWT tokens with built-in Next.js components.
``bash`
npm install @logickernel/bridge
Add these to the .env file of your application:
`bash`
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 redirects
In your next.config.ts, add the bridge package to transpilePackages:
`typescript
import type { NextConfig } from "next"
const nextConfig: NextConfig = {
transpilePackages: ["@logickernel/bridge"],
// ... other config
}
export default nextConfig
`
Use webpack instead of Turbopack (the default) in your package.json scripts:
`json`
{
"scripts": {
"dev": "next dev --webpack",
"build": "next build --webpack"
}
}
Add the @source directive to your src/app/globals.css to ensure Tailwind scans classes from this package:
`css
@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.
Create a wrapper component to establish the client/server boundary:
`typescript
"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 (
apiBaseUrl={apiBaseUrl}
>
{children}
)
}
`
Use in your layout:
`tsx
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 (
{children}
)
}
`
The layout automatically fetches user information from the 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:
`typescript
{
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.
- 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
`tsx
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
$3
`tsx
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
Admin Panel for {auth.session.user.email}
}
`$3
`typescript
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
}
)
`$3
`typescript
// 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
`typescript
// 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
$3
| 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 |$3
| 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 |$3
| 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:
`typescript
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
`typescript
// 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
`bash
Install dependencies
npm installBuild the library
npm run buildWatch mode for development
npm run devType checking
npm run typecheckClean build artifacts
npm run clean
``MIT