Integrating Auth
ShellApps ID provides a unified identity system across the entire ShellApps platform. This guide covers integrating authentication into your app.
How ShellApps ID Works
ShellApps ID is the single sign-on (SSO) identity layer for all ShellApps services. Users create one account and use it across every ShellApp.
Key concepts:
- ShellApps ID — The user's identity, managed at auth.shellapps.com (opens in a new tab)
- Profiles — Users can have multiple profiles (personal, work, etc.) under one ID
- Sessions — JWT-based sessions with automatic refresh
- OAuth 2.0 — Standard OAuth 2.0 / OIDC flow for third-party apps
Adding Login / Signup to Your App
Install the Auth SDK
npm install @shellapps/auth-sdkConfigure the Auth Provider
app/auth-provider.tsx
'use client'
import { AuthProvider } from '@shellapps/auth-sdk'
export function ShellAuthProvider({ children }: { children: React.ReactNode }) {
return (
<AuthProvider
appId={process.env.NEXT_PUBLIC_SHELLAPPS_APP_ID!}
redirectUri={process.env.NEXT_PUBLIC_AUTH_REDIRECT_URI!}
>
{children}
</AuthProvider>
)
}Add Login / Signup Buttons
components/auth-buttons.tsx
'use client'
import { useAuth } from '@shellapps/auth-sdk'
import { Button } from '@shellapps/react-ui'
export function AuthButtons() {
const { user, login, signup, logout, isLoading } = useAuth()
if (isLoading) return null
if (user) {
return (
<div>
<span>Hello, {user.displayName}</span>
<Button onClick={logout} variant="ghost">Sign Out</Button>
</div>
)
}
return (
<div>
<Button onClick={login} variant="primary">Log In</Button>
<Button onClick={signup} variant="outline">Sign Up</Button>
</div>
)
}Using the Auth SDK
Access the Current User
import { useAuth } from '@shellapps/auth-sdk'
function Dashboard() {
const { user, accessToken } = useAuth()
// Use accessToken for API calls
const res = await fetch('/api/data', {
headers: { Authorization: `Bearer ${accessToken}` }
})
}Server-Side Authentication
app/api/protected/route.ts
import { verifyToken } from '@shellapps/auth-sdk/server'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(req: NextRequest) {
const token = req.headers.get('Authorization')?.replace('Bearer ', '')
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
try {
const user = await verifyToken(token, {
appId: process.env.SHELLAPPS_APP_ID!,
})
return NextResponse.json({ user })
} catch {
return NextResponse.json({ error: 'Invalid token' }, { status: 401 })
}
}Session Management
Sessions are managed automatically by the Auth SDK. Tokens are stored securely and refreshed in the background.
const { user, accessToken, refreshSession, isExpired } = useAuth()
// Force refresh if needed
if (isExpired) {
await refreshSession()
}Session Configuration
<AuthProvider
appId={process.env.NEXT_PUBLIC_SHELLAPPS_APP_ID!}
redirectUri="/auth/callback"
sessionConfig={{
autoRefresh: true,
refreshInterval: 300, // seconds
persistSession: true,
storage: 'cookie', // 'cookie' | 'localStorage'
}}
>Profile Switching
Users with multiple profiles can switch between them without re-authenticating.
import { useAuth } from '@shellapps/auth-sdk'
function ProfileSwitcher() {
const { user, profiles, switchProfile, activeProfile } = useAuth()
return (
<select
value={activeProfile.id}
onChange={(e) => switchProfile(e.target.value)}
>
{profiles.map((profile) => (
<option key={profile.id} value={profile.id}>
{profile.displayName} ({profile.type})
</option>
))}
</select>
)
}Protecting Routes
Client-Side Route Protection
components/protected-route.tsx
'use client'
import { useAuth } from '@shellapps/auth-sdk'
import { redirect } from 'next/navigation'
export function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { user, isLoading } = useAuth()
if (isLoading) return <div>Loading...</div>
if (!user) redirect('/login')
return <>{children}</>
}Middleware-Based Protection
middleware.ts
import { withAuth } from '@shellapps/auth-sdk/middleware'
export default withAuth({
appId: process.env.SHELLAPPS_APP_ID!,
protectedRoutes: ['/dashboard/:path*', '/settings/:path*'],
loginPage: '/login',
})
export const config = {
matcher: ['/dashboard/:path*', '/settings/:path*'],
}Next Steps
- Quick Start — Build your first ShellApp
- Deployment — Deploy with auth configured
- Architecture — How auth fits into the platform