auth0
Definitive guidelines for integrating Auth0 securely and efficiently, preventing common identity attacks, and leveraging modern authentication patterns.
The skill
# auth0 Best Practices
This guide outlines the definitive best practices for integrating Auth0 into our applications. Adhering to these standards is critical for maintaining a robust security posture against modern identity threats.
## 1. Prioritize Universal Login
Always centralize authentication flows using Auth0 Universal Login. This offloads complex security logic, ensures consistency, and leverages Auth0's built-in security features across all applications (web, mobile, AI agents).
❌ **BAD: Implementing custom login forms or embedded login**
This introduces significant security risks and maintenance overhead.
✅ **GOOD: Redirecting to Universal Login with Auth0 SDKs**
```javascript
// Example for a React/SPA using @auth0/auth0-react (built on auth0-spa-js)
import { useAuth0 } from '@auth0/auth0-react';
function LoginButton() {
const { loginWithRedirect } = useAuth0();
const handleLogin = () => {
loginWithRedirect({
appState: { targetUrl: window.location.pathname },
authorizationParams: {
redirect_uri: window.location.origin + '/callback',
scope: 'openid profile email', // Request only necessary scopes
},
});
};
return <button onClick={handleLogin}>Log In</button>;
}
```
## 2. Enforce Authorization Code Flow with PKCE
For all public clients (SPAs, mobile apps, native desktop apps), the Authorization Code Flow with Proof Key for Code Exchange (PKCE) is the *only* acceptable grant type. This prevents authorization code injection attacks. **Never use Implicit Grant or Resource Owner Password Grant (ROPG).**
❌ **BAD: Using Implicit Grant or ROPG**
These flows are deprecated and highly vulnerable.
```javascript
// ❌ BAD: Implicit Grant (responseType: 'token id_token')
// Avoid configuring your Auth0 application to allow this.
// ❌ BAD: ROPG (sending username/password directly to /oauth/token)
// Never trust the client with user credentials.
```
✅ **GOOD: Authorization Code Flow with PKCE**
Ensure your Auth0 application is configured for PKCE, and your SDK handles the `code_challenge` and `code_verifier`.
```go
// Example for a Go backend (handling Auth0 callback)
package main
import (
"context"
"log"
"net/http"
"github.com/auth0/go-auth0/v2/authentication"
"github.com/auth0/go-auth0/v2/authentication/oauth"
)
// authAPI and tokenValidator are initialized once at application startup (see below)
var authAPI *authentication.Authentication
// init function (or similar setup) for authAPI
func initAuthAPI() {
var err error
authAPI, err = authentication.New(
context.Background(),
"example.us.auth0.com", // Replace with your Auth0 tenant domain
authentication.WithClientID("YOUR_CLIENT_ID"),
authentication.WithClientSecret("YOUR_CLIENT_SECRET"), // For backend apps
)
if err != nil {
log.Fatalf("Failed to initialize Auth0 authentication API client: %+v", err)
}
}
func handleAuth0Callback(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
// In a real app, codeVerifier must be retrieved from a secure, short-lived storage
// (e.g., session) associated with the user's browser session.
codeVerifier := r.Context().Value("code_verifier").(string) // Placeholder
tokenSet, err := authAPI.OAuth.LoginWithAuthCodeWithPKCE(r.Context(), oauth.LoginWithAuthCodeWithPKCERequest{
Code: code,
CodeVerifier: codeVerifier,
RedirectURI: "https://your-app.com/callback", // Must match configured callback URL
}, oauth.IDTokenValidationOptions{})
if err != nil {
log.Printf("Failed to exchange code for tokens: %v", err)
http.Error(w, "Authentication failed", http.StatusInternalServerError)
return
}
// ✅ GOOD: Store tokenSet securely (e.g., in an HTTP-only, Secure cookie for web apps)
// Do NOT expose tokens to client-side JavaScript unnecessarily.
log.Printf("Successfully authenticated user: %s", tokenSet.IDToken)
http.Redirect(w, r, "/dashboard", http.StatusFound)
How to install it
1. Open the tool and start a new conversation, project or template. 2. Paste the text below wherever the tool keeps standing instructions — usually called system prompt, instructions, or persona. 3. Save it so it applies to every run rather than a single message.