[{"data":1,"prerenderedAt":426},["ShallowReactive",2],{"blog-guides/auth0":3},{"id":4,"title":5,"body":6,"category":398,"date":399,"dateModified":399,"description":400,"draft":401,"extension":402,"faq":403,"featured":401,"headerVariant":410,"image":411,"keywords":412,"meta":413,"navigation":414,"ogDescription":415,"ogTitle":411,"path":416,"readTime":417,"schemaOrg":418,"schemaType":419,"seo":420,"sitemap":421,"stem":422,"tags":423,"twitterCard":424,"__hash__":425},"blog/blog/guides/auth0.md","Auth0 Security Guide for Vibe Coders",{"type":7,"value":8,"toc":372},"minimark",[9,16,21,24,27,31,36,47,61,65,68,74,83,87,90,94,100,104,110,114,117,121,151,155,161,169,173,179,183,187,190,196,200,206,210,213,219,224,263,267,270,276,304,308,311,334,341,360],[10,11,12],"tldr",{},[13,14,15],"p",{},"Auth0 handles authentication, but security still depends on your implementation. Always validate tokens server-side with proper audience and issuer checks. Use RBAC for authorization instead of client-side checks. Configure callback URLs precisely (no wildcards in production). Keep your client secret actually secret, and rotate it if exposed.",[17,18,20],"h2",{"id":19},"why-auth0-security-matters-for-vibe-coding","Why Auth0 Security Matters for Vibe Coding",[13,22,23],{},"Auth0 is one of the most popular authentication platforms for modern applications. When AI tools generate Auth0 integration code, they often produce working authentication flows but miss critical security validations. The SDK handles the happy path, but security requires attention to edge cases and proper configuration.",[13,25,26],{},"Common issues include missing server-side token validation, overly permissive callback URLs, exposed client secrets, and authorization checks that only happen on the frontend.",[17,28,30],{"id":29},"configuration-security","Configuration Security",[32,33,35],"h3",{"id":34},"environment-variables","Environment Variables",[37,38,43],"pre",{"className":39,"code":41,"language":42},[40],"language-text","# .env.local (never commit)\nAUTH0_SECRET=\"use-a-32-character-minimum-random-string\"\nAUTH0_BASE_URL=\"https://yourdomain.com\"\nAUTH0_ISSUER_BASE_URL=\"https://your-tenant.auth0.com\"\nAUTH0_CLIENT_ID=\"your-client-id\"\nAUTH0_CLIENT_SECRET=\"your-client-secret\"  # Keep this secret!\n\n# For API token validation\nAUTH0_AUDIENCE=\"https://api.yourdomain.com\"\n","text",[44,45,41],"code",{"__ignoreMap":46},"",[48,49,50],"danger-box",{},[13,51,52,56,57,60],{},[53,54,55],"strong",{},"Never Expose Your Client Secret:"," The ",[44,58,59],{},"AUTH0_CLIENT_SECRET"," must never be exposed to the browser or committed to version control. It should only exist in server-side environment variables. If it's exposed, rotate it immediately in the Auth0 dashboard.",[32,62,64],{"id":63},"callback-url-configuration","Callback URL Configuration",[13,66,67],{},"In your Auth0 dashboard, configure callback URLs precisely:",[37,69,72],{"className":70,"code":71,"language":42},[40],"# CORRECT: Specific URLs\nAllowed Callback URLs:\n  https://yourdomain.com/api/auth/callback\n  https://staging.yourdomain.com/api/auth/callback\n\nAllowed Logout URLs:\n  https://yourdomain.com\n  https://staging.yourdomain.com\n\n# DANGEROUS: Wildcards (never use in production)\nAllowed Callback URLs:\n  https://*.yourdomain.com/*  # Attackers can register subdomains!\n  http://localhost:*/*        # Development only, remove for production\n",[44,73,71],{"__ignoreMap":46},[75,76,77],"warning-box",{},[13,78,79,82],{},[53,80,81],{},"Wildcard Callbacks Enable Attacks:"," Wildcard callback URLs allow attackers to redirect authentication to malicious endpoints. If an attacker can create a subdomain or find an open redirect on your site, they can steal tokens. Always use exact URLs in production.",[17,84,86],{"id":85},"token-validation","Token Validation",[13,88,89],{},"Every API route must validate tokens server-side. Never trust tokens without verification.",[32,91,93],{"id":92},"nextjs-api-route-protection","Next.js API Route Protection",[37,95,98],{"className":96,"code":97,"language":42},[40],"// middleware.ts - Protect all API routes\nimport { withMiddlewareAuthRequired } from '@auth0/nextjs-auth0/edge';\n\nexport default withMiddlewareAuthRequired();\n\nexport const config = {\n  matcher: ['/api/:path*', '/dashboard/:path*']\n};\n",[44,99,97],{"__ignoreMap":46},[32,101,103],{"id":102},"manual-token-validation","Manual Token Validation",[37,105,108],{"className":106,"code":107,"language":42},[40],"// For custom validation or non-Next.js apps\nimport { jwtVerify } from 'jose';\n\nasync function validateToken(token: string) {\n  const JWKS = jose.createRemoteJWKSet(\n    new URL(`${process.env.AUTH0_ISSUER_BASE_URL}/.well-known/jwks.json`)\n  );\n\n  try {\n    const { payload } = await jwtVerify(token, JWKS, {\n      // CRITICAL: Verify these claims\n      issuer: process.env.AUTH0_ISSUER_BASE_URL + '/',\n      audience: process.env.AUTH0_AUDIENCE,\n    });\n\n    // Additional validation\n    if (!payload.sub) {\n      throw new Error('Missing subject claim');\n    }\n\n    return payload;\n  } catch (error) {\n    console.error('Token validation failed:', error);\n    throw new Error('Invalid token');\n  }\n}\n\n// Usage in API route\nexport async function GET(request: Request) {\n  const authHeader = request.headers.get('authorization');\n\n  if (!authHeader?.startsWith('Bearer ')) {\n    return Response.json({ error: 'Missing token' }, { status: 401 });\n  }\n\n  const token = authHeader.slice(7);\n\n  try {\n    const payload = await validateToken(token);\n    // Token is valid, proceed with request\n    return Response.json({ userId: payload.sub });\n  } catch {\n    return Response.json({ error: 'Invalid token' }, { status: 401 });\n  }\n}\n",[44,109,107],{"__ignoreMap":46},[17,111,113],{"id":112},"role-based-access-control-rbac","Role-Based Access Control (RBAC)",[13,115,116],{},"Auth0's RBAC allows you to define permissions and assign them to users via roles. Always verify permissions server-side.",[32,118,120],{"id":119},"setting-up-rbac-in-auth0","Setting Up RBAC in Auth0",[122,123,124,128,131,145,148],"ol",{},[125,126,127],"li",{},"Go to Dashboard > Applications > APIs > Your API",[125,129,130],{},"Enable \"Enable RBAC\" and \"Add Permissions in the Access Token\"",[125,132,133,134,137,138,137,141,144],{},"Define permissions (e.g., ",[44,135,136],{},"read:documents",", ",[44,139,140],{},"write:documents",[44,142,143],{},"admin:users",")",[125,146,147],{},"Create roles and assign permissions",[125,149,150],{},"Assign roles to users",[32,152,154],{"id":153},"checking-permissions-server-side","Checking Permissions Server-Side",[37,156,159],{"className":157,"code":158,"language":42},[40],"// utils/permissions.ts\nimport { getSession } from '@auth0/nextjs-auth0';\n\nexport async function hasPermission(permission: string): Promise\u003Cboolean> {\n  const session = await getSession();\n\n  if (!session?.accessToken) {\n    return false;\n  }\n\n  // Decode the access token to get permissions\n  const payload = JSON.parse(\n    Buffer.from(session.accessToken.split('.')[1], 'base64').toString()\n  );\n\n  const permissions = payload.permissions || [];\n  return permissions.includes(permission);\n}\n\n// API route with permission check\nexport async function DELETE(request: Request, { params }: { params: { id: string } }) {\n  // First check authentication\n  const session = await getSession();\n  if (!session) {\n    return Response.json({ error: 'Unauthorized' }, { status: 401 });\n  }\n\n  // Then check authorization (permission)\n  if (!await hasPermission('delete:documents')) {\n    return Response.json({ error: 'Forbidden' }, { status: 403 });\n  }\n\n  // User is authenticated AND authorized\n  await deleteDocument(params.id);\n  return Response.json({ success: true });\n}\n",[44,160,158],{"__ignoreMap":46},[75,162,163],{},[13,164,165,168],{},[53,166,167],{},"Never Rely on Frontend Permission Checks:"," Frontend checks should only be used for UX (hiding buttons, etc.). Always verify permissions on the server before performing any action. Users can modify frontend code or call APIs directly.",[17,170,172],{"id":171},"secure-session-management","Secure Session Management",[37,174,177],{"className":175,"code":176,"language":42},[40],"// auth0.ts - Configure session security\nimport { initAuth0 } from '@auth0/nextjs-auth0';\n\nexport default initAuth0({\n  secret: process.env.AUTH0_SECRET,\n  issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,\n  baseURL: process.env.AUTH0_BASE_URL,\n  clientID: process.env.AUTH0_CLIENT_ID,\n  clientSecret: process.env.AUTH0_CLIENT_SECRET,\n\n  session: {\n    // Use rolling sessions\n    rolling: true,\n    // Absolute timeout\n    absoluteDuration: 60 * 60 * 24 * 7, // 7 days\n    // Inactivity timeout\n    rollingDuration: 60 * 60 * 24, // 1 day of inactivity\n\n    cookie: {\n      // Secure in production\n      secure: process.env.NODE_ENV === 'production',\n      // Strict same-site policy\n      sameSite: 'lax',\n      // HTTP-only prevents XSS access\n      httpOnly: true,\n    }\n  },\n\n  authorizationParams: {\n    // Request specific scopes\n    scope: 'openid profile email',\n    // Include audience for API access\n    audience: process.env.AUTH0_AUDIENCE,\n  }\n});\n",[44,178,176],{"__ignoreMap":46},[17,180,182],{"id":181},"protecting-against-common-attacks","Protecting Against Common Attacks",[32,184,186],{"id":185},"csrf-protection","CSRF Protection",[13,188,189],{},"Auth0's SDK includes CSRF protection, but verify it's working:",[37,191,194],{"className":192,"code":193,"language":42},[40],"// The SDK automatically adds state parameter\n// Verify it's present in your callback handling\n\n// If implementing custom callback:\nexport async function GET(request: Request) {\n  const { searchParams } = new URL(request.url);\n  const state = searchParams.get('state');\n  const code = searchParams.get('code');\n\n  if (!state) {\n    return Response.json({ error: 'Missing state parameter' }, { status: 400 });\n  }\n\n  // Verify state matches what was sent\n  const savedState = cookies().get('auth_state')?.value;\n  if (state !== savedState) {\n    return Response.json({ error: 'State mismatch' }, { status: 400 });\n  }\n\n  // Continue with token exchange...\n}\n",[44,195,193],{"__ignoreMap":46},[32,197,199],{"id":198},"token-storage","Token Storage",[37,201,204],{"className":202,"code":203,"language":42},[40],"// CORRECT: Let Auth0 SDK handle token storage (HTTP-only cookies)\n// The SDK stores tokens securely server-side\n\n// DANGEROUS: Storing tokens in localStorage\nlocalStorage.setItem('access_token', token); // XSS can steal this!\n\n// DANGEROUS: Storing tokens in sessionStorage\nsessionStorage.setItem('access_token', token); // XSS can steal this!\n\n// If you must pass tokens to the frontend (for SPA APIs):\n// Use short-lived tokens and refresh via server-side route\n",[44,205,203],{"__ignoreMap":46},[17,207,209],{"id":208},"multi-factor-authentication","Multi-Factor Authentication",[13,211,212],{},"Enable and enforce MFA for sensitive operations:",[37,214,217],{"className":215,"code":216,"language":42},[40],"// Auth0 Rule or Action to enforce MFA\nexports.onExecutePostLogin = async (event, api) => {\n  // Require MFA for admin users\n  const roles = event.authorization?.roles || [];\n\n  if (roles.includes('admin')) {\n    // Check if MFA was used in this session\n    if (event.authentication?.methods) {\n      const mfaUsed = event.authentication.methods.some(\n        m => m.name === 'mfa'\n      );\n\n      if (!mfaUsed) {\n        // Trigger MFA challenge\n        api.multifactor.enable('any');\n      }\n    }\n  }\n};\n",[44,218,216],{"__ignoreMap":46},[220,221,223],"h4",{"id":222},"auth0-security-checklist","Auth0 Security Checklist",[225,226,227,230,233,236,239,242,245,248,251,254,257,260],"ul",{},[125,228,229],{},"Client secret stored in server-side environment variables only",[125,231,232],{},"Callback URLs are exact matches (no wildcards in production)",[125,234,235],{},"All API routes validate tokens server-side",[125,237,238],{},"Token validation checks issuer AND audience",[125,240,241],{},"RBAC permissions verified on server before actions",[125,243,244],{},"Sessions use HTTP-only, secure, SameSite cookies",[125,246,247],{},"Session timeouts configured appropriately",[125,249,250],{},"MFA enabled for admin accounts",[125,252,253],{},"Tokens never stored in localStorage/sessionStorage",[125,255,256],{},"CSRF protection enabled (state parameter)",[125,258,259],{},"Refresh tokens rotated on use",[125,261,262],{},"Auth0 tenant has brute force protection enabled",[17,264,266],{"id":265},"logging-and-monitoring","Logging and Monitoring",[13,268,269],{},"Auth0 provides extensive logging. Use it for security monitoring:",[37,271,274],{"className":272,"code":273,"language":42},[40],"// Set up Auth0 Log Streaming to your SIEM\n// Or use the Management API to fetch logs\n\nimport { ManagementClient } from 'auth0';\n\nconst management = new ManagementClient({\n  domain: process.env.AUTH0_DOMAIN,\n  clientId: process.env.AUTH0_MANAGEMENT_CLIENT_ID,\n  clientSecret: process.env.AUTH0_MANAGEMENT_CLIENT_SECRET,\n});\n\n// Fetch recent security events\nconst logs = await management.logs.getAll({\n  q: 'type:f OR type:fu OR type:fp', // Failed logins\n  sort: 'date:-1',\n  per_page: 100,\n});\n\n// Alert on suspicious patterns\nconst failedAttempts = logs.filter(log =>\n  log.type === 'f' && // Failed login\n  log.ip === suspiciousIP\n);\n\nif (failedAttempts.length > 10) {\n  await alertSecurityTeam('Brute force attempt detected');\n}\n",[44,275,273],{"__ignoreMap":46},[277,278,279,286,292,298],"faq-section",{},[280,281,283],"faq-item",{"question":282},"Should I validate tokens on every API request?",[13,284,285],{},"Yes. Every API request should validate the token. Auth0's middleware and SDK do this automatically, but if you're implementing custom routes, ensure validation happens. Token validation is fast (using cached JWKS) and essential for security.",[280,287,289],{"question":288},"What's the difference between ID tokens and access tokens?",[13,290,291],{},"ID tokens contain user information (name, email) and are meant for your application to identify the user. Access tokens are for authorizing API requests and should contain permissions/scopes. Never send ID tokens to external APIs.",[280,293,295],{"question":294},"How do I handle token expiration?",[13,296,297],{},"Use refresh tokens to get new access tokens before they expire. Auth0's SDK handles this automatically. For SPAs, use silent authentication or refresh token rotation. Never extend access token lifetimes beyond what's necessary.",[280,299,301],{"question":300},"Can I trust the user's roles from the frontend?",[13,302,303],{},"No. Roles and permissions shown on the frontend are for UX only. Always verify roles/permissions server-side by checking the access token's claims. Users can modify frontend code to show any role they want.",[17,305,307],{"id":306},"what-checkyourvibe-detects","What CheckYourVibe Detects",[13,309,310],{},"When scanning your Auth0-integrated project, CheckYourVibe identifies:",[225,312,313,316,319,322,325,328,331],{},[125,314,315],{},"Client secrets exposed in frontend code",[125,317,318],{},"Missing server-side token validation",[125,320,321],{},"API routes without authentication middleware",[125,323,324],{},"Wildcard callback URLs in configuration",[125,326,327],{},"Tokens stored in localStorage/sessionStorage",[125,329,330],{},"Missing audience validation in token checks",[125,332,333],{},"Frontend-only permission checks",[13,335,336,337,340],{},"Run ",[44,338,339],{},"npx checkyourvibe scan"," to catch these issues before they reach production.",[342,343,344,350,355],"related-articles",{},[345,346],"related-card",{"description":347,"href":348,"title":349},"Row-level security and auth patterns","/blog/guides/supabase","Supabase Security Guide",[345,351],{"description":352,"href":353,"title":354},"Security rules and authentication","/blog/guides/firebase","Firebase Security Guide",[345,356],{"description":357,"href":358,"title":359},"Best practices for key management","/blog/how-to/secure-api-keys","Secure API Keys",[361,362,365,369],"cta-box",{"href":363,"label":364},"/","Start Free Scan",[17,366,368],{"id":367},"scan-your-auth0-integration","Scan Your Auth0 Integration",[13,370,371],{},"Find token validation issues, exposed secrets, and configuration problems before they become security incidents.",{"title":46,"searchDepth":373,"depth":373,"links":374},2,[375,376,381,385,389,390,394,395,396,397],{"id":19,"depth":373,"text":20},{"id":29,"depth":373,"text":30,"children":377},[378,380],{"id":34,"depth":379,"text":35},3,{"id":63,"depth":379,"text":64},{"id":85,"depth":373,"text":86,"children":382},[383,384],{"id":92,"depth":379,"text":93},{"id":102,"depth":379,"text":103},{"id":112,"depth":373,"text":113,"children":386},[387,388],{"id":119,"depth":379,"text":120},{"id":153,"depth":379,"text":154},{"id":171,"depth":373,"text":172},{"id":181,"depth":373,"text":182,"children":391},[392,393],{"id":185,"depth":379,"text":186},{"id":198,"depth":379,"text":199},{"id":208,"depth":373,"text":209},{"id":265,"depth":373,"text":266},{"id":306,"depth":373,"text":307},{"id":367,"depth":373,"text":368},"guides","2026-01-14","Secure your Auth0 authentication when vibe coding. Learn token validation, RBAC configuration, secure callback handling, and common misconfigurations to avoid.",false,"md",[404,406,408],{"question":282,"answer":405},"Yes. Every API request should validate the token. Auth0's middleware and SDK do this automatically.",{"question":288,"answer":407},"ID tokens contain user information and are for identifying the user. Access tokens are for authorizing API requests and should contain permissions/scopes.",{"question":300,"answer":409},"No. Always verify roles/permissions server-side by checking the access token's claims.","blue",null,"Auth0 security, vibe coding authentication, JWT validation, RBAC Auth0, OAuth security, token security",{},true,"Secure your Auth0 authentication with proper token validation, RBAC, and callback handling.","/blog/guides/auth0","14 min read","[object Object]","TechArticle",{"title":5,"description":400},{"loc":416},"blog/guides/auth0",[],"summary_large_image","NVhN5_XZOySMcKMSsrKxJNkfAfW01O18iTgLBFo4hxU",1775843930325]