Files
gh-varaku1012-aditi-code-pl…/commands/oauth-implement.md
2025-11-30 09:04:20 +08:00

9.5 KiB

description
description
Framework-specific implementation guide for adding Auth0 OAuth to your application

OAuth Implementation Guide

Detailed code walkthrough for implementing Auth0 authentication in your framework.

Quick Start

/oauth-implement [framework]

Supported frameworks:

  • react - React with Create React App or Vite
  • nextjs - Next.js (13+ with App Router recommended)
  • nodejs - Node.js/Express backend
  • fastapi - Python FastAPI
  • django - Python Django
  • vue - Vue.js
  • svelte - Svelte
  • flutter - Flutter mobile
  • react-native - React Native mobile

Implementation Steps by Framework

React (SPA)

1. Install Auth0 React SDK

npm install @auth0/auth0-react

2. Wrap App with Auth0Provider

// src/main.tsx
import { Auth0Provider } from '@auth0/auth0-react'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <Auth0Provider
    domain={import.meta.env.VITE_AUTH0_DOMAIN}
    clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
    authorizationParams={{
      redirect_uri: window.location.origin,
      scope: 'openid profile email read:items',
      audience: `https://${import.meta.env.VITE_AUTH0_DOMAIN}/api/v2/`
    }}
    cacheLocation="memory"
  >
    <App />
  </Auth0Provider>
)

3. Create Login/Logout Components

// src/components/Auth.tsx
import { useAuth0 } from '@auth0/auth0-react'

export function LoginButton() {
  const { loginWithRedirect, isAuthenticated } = useAuth0()
  if (isAuthenticated) return null
  return <button onClick={() => loginWithRedirect()}>Login</button>
}

export function LogoutButton() {
  const { logout, isAuthenticated } = useAuth0()
  if (!isAuthenticated) return null
  return <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}>Logout</button>
}

export function Profile() {
  const { user, isAuthenticated } = useAuth0()
  if (!isAuthenticated) return <p>Not logged in</p>
  return (
    <div>
      <img src={user?.picture} alt={user?.name} />
      <h2>{user?.name}</h2>
      <p>{user?.email}</p>
    </div>
  )
}

4. Protected Routes

// src/components/ProtectedRoute.tsx
import { useAuth0 } from '@auth0/auth0-react'

export function ProtectedRoute({ children }: any) {
  const { isAuthenticated, isLoading } = useAuth0()

  if (isLoading) return <div>Loading...</div>
  if (!isAuthenticated) return <div>Please log in</div>

  return children
}

// In App.tsx
<Routes>
  <Route path="/dashboard" element={<ProtectedRoute><Dashboard /></ProtectedRoute>} />
</Routes>

5. Call Protected API

// src/hooks/useApi.ts
import { useAuth0 } from '@auth0/auth0-react'
import { useEffect, useState } from 'react'

export function useApi<T>(url: string) {
  const { getAccessTokenSilently } = useAuth0()
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<Error | null>(null)

  useEffect(() => {
    let isMounted = true

    const fetchData = async () => {
      try {
        const token = await getAccessTokenSilently()
        const response = await fetch(url, {
          headers: { Authorization: `Bearer ${token}` }
        })
        if (!response.ok) throw new Error('API error')
        const result = await response.json()
        if (isMounted) setData(result)
      } catch (err) {
        if (isMounted) setError(err instanceof Error ? err : new Error('Unknown error'))
      } finally {
        if (isMounted) setLoading(false)
      }
    }

    fetchData()
    return () => { isMounted = false }
  }, [url, getAccessTokenSilently])

  return { data, error, loading }
}

6. Environment Variables

VITE_AUTH0_DOMAIN=YOUR_DOMAIN.auth0.com
VITE_AUTH0_CLIENT_ID=YOUR_CLIENT_ID

Next.js (Full-Stack)

1. Install SDK

npm install @auth0/nextjs-auth0

2. Create Auth Routes

App Router (Recommended):

// app/api/auth/[auth0]/route.ts
import { handleAuth } from '@auth0/nextjs-auth0'

export const GET = handleAuth()

Pages Router:

// pages/api/auth/[auth0].ts
import { handleAuth } from '@auth0/nextjs-auth0'

export default handleAuth()

3. Access User in Components

App Router:

// app/profile/page.tsx
import { getSession } from '@auth0/nextjs-auth0'
import { redirect } from 'next/navigation'

export default async function ProfilePage() {
  const session = await getSession()

  if (!session) {
    redirect('/api/auth/login')
  }

  return (
    <div>
      <h1>Welcome, {session.user.name}</h1>
      <img src={session.user.picture} alt={session.user.name} />
    </div>
  )
}
// app/components/Nav.tsx
import { getSession } from '@auth0/nextjs-auth0'

export async function Nav() {
  const session = await getSession()

  return (
    <nav>
      {session ? (
        <>
          <span>{session.user.name}</span>
          <a href="/api/auth/logout">Logout</a>
        </>
      ) : (
        <a href="/api/auth/login">Login</a>
      )}
    </nav>
  )
}

5. Call API with Token

// app/api/items/route.ts
import { getSession } from '@auth0/nextjs-auth0'
import { NextResponse } from 'next/server'

export async function GET() {
  const session = await getSession()

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

  const response = await fetch('http://localhost:3001/items', {
    headers: { Authorization: `Bearer ${session.accessToken}` }
  })

  return NextResponse.json(await response.json())
}

6. Environment Variables

AUTH0_SECRET='[generated secret]'
AUTH0_BASE_URL='http://localhost:3000'
AUTH0_ISSUER_BASE_URL='https://YOUR_DOMAIN.auth0.com'
AUTH0_CLIENT_ID='YOUR_CLIENT_ID'
AUTH0_CLIENT_SECRET='YOUR_CLIENT_SECRET'

Node.js/Express Backend

1. Install Dependencies

npm install express-jwt jwks-rsa

2. Create JWT Middleware

// middleware/auth.ts
import { expressjwt as jwt } from 'express-jwt'
import jwksRsa from 'jwks-rsa'

const checkJwt = jwt({
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`
  }),
  audience: `https://${process.env.AUTH0_DOMAIN}/api/v2/`,
  issuer: `https://${process.env.AUTH0_DOMAIN}/`,
  algorithms: ['RS256']
})

export default checkJwt

3. Protect Routes

// routes/items.ts
import express from 'express'
import checkJwt from '../middleware/auth'

const router = express.Router()

router.get('/public', (req, res) => {
  res.json({ message: 'Public' })
})

router.get('/items', checkJwt, (req, res) => {
  // req.auth contains decoded JWT
  res.json({ userId: req.auth.sub, items: [] })
})

// Scope validation
router.delete('/items/:id', checkJwt, (req, res) => {
  const scope = req.auth.scope?.split(' ') || []

  if (!scope.includes('delete:items')) {
    return res.status(403).json({ error: 'Insufficient permissions' })
  }

  res.json({ message: 'Item deleted' })
})

export default router

FastAPI (Python)

# main.py
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthCredentials
import jwt
from jwt import algorithms

app = FastAPI()
security = HTTPBearer()

DOMAIN = "YOUR_DOMAIN.auth0.com"

async def verify_token(credentials: HTTPAuthCredentials = Depends(security)):
    token = credentials.credentials

    try:
        # Get public key
        jwks_client = jwt.PyJWKClient(f"https://{DOMAIN}/.well-known/jwks.json")
        signing_key = jwks_client.get_signing_key_from_jwt(token)

        # Verify token
        payload = jwt.decode(
            token,
            signing_key.key,
            algorithms=["RS256"],
            audience=f"https://{DOMAIN}/api/v2/",
            issuer=f"https://{DOMAIN}/"
        )

        return payload
    except Exception as e:
        raise HTTPException(status_code=401, detail="Invalid token")

@app.get("/items")
async def get_items(user: dict = Depends(verify_token)):
    return { "user_id": user["sub"], "items": [] }

Testing Implementation

Test Login Flow

# 1. Visit login page
open http://localhost:3000/api/auth/login

# 2. Complete auth flow in Auth0
# 3. Check if callback works

# 4. Test API
curl -H "Authorization: Bearer <ACCESS_TOKEN>" \
  http://localhost:3001/api/items

Inspect Token (React)

// In browser console
const token = await auth0.getAccessTokenSilently()
console.log(token)

// Decode at jwt.io

Common Issues & Solutions

Issue Solution
Token expired SDK auto-refreshes, check refresh token rotation enabled
CORS error Configure CORS in backend, check Auth0 allowed origins
Silent auth fails Check cacheLocation: "memory", try explicit login
Scope not in token Add to Auth0 rule or API scopes config
Token validation fails Verify audience, issuer, algorithms match

Next Steps

  1. Test implementation with /oauth-security-audit
  2. Run /oauth-troubleshoot for any issues
  3. Deploy and update callback URLs to production domain

Status: Implementation guide ready!