Back to skills
SkillHub ClubDesign ProductFull StackDesignerSecurity

authentication-setup

Design and implement authentication and authorization systems. Use when setting up user login, JWT tokens, OAuth, session management, or role-based access control. Handles password security, token management, SSO integration.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
68
Hot score
92
Updated
March 19, 2026
Overall rating
C3.4
Composite score
3.4
Best-practice grade
B73.6

Install command

npx @skill-hub/cli install supercent-io-skills-template-authentication-setup

Repository

supercent-io/skills-template

Skill path: .agent-skills/authentication-setup

Design and implement authentication and authorization systems. Use when setting up user login, JWT tokens, OAuth, session management, or role-based access control. Handles password security, token management, SSO integration.

Open repository

Best for

Primary workflow: Design Product.

Technical facets: Full Stack, Designer, Security, Integration.

Target audience: everyone.

License: Apache-2.0.

Original source

Catalog source: SkillHub Club.

Repository owner: supercent-io.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install authentication-setup into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/supercent-io/skills-template before adding authentication-setup to shared team environments
  • Use authentication-setup for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: authentication-setup
description: Design and implement authentication and authorization systems. Use when setting up user login, JWT tokens, OAuth, session management, or role-based access control. Handles password security, token management, SSO integration.
metadata:
  tags: authentication, authorization, security, JWT, OAuth, RBAC
  platforms: Claude, ChatGPT, Gemini
---


# Authentication Setup


## When to use this skill

Lists specific situations where this skill should be triggered:

- **User Login System**: When adding user authentication to a new application
- **API Security**: When adding an authentication layer to a REST or GraphQL API
- **Permission Management**: When role-based access control is needed
- **Authentication Migration**: When migrating an existing auth system to JWT or OAuth
- **SSO Integration**: When integrating social login with Google, GitHub, Microsoft, etc.

## Input Format

The required and optional input information to collect from the user:

### Required Information
- **Authentication Method**: Choose from JWT, Session, or OAuth 2.0
- **Backend Framework**: Express, Django, FastAPI, Spring Boot, etc.
- **Database**: PostgreSQL, MySQL, MongoDB, etc.
- **Security Requirements**: Password policy, token expiry times, etc.

### Optional Information
- **MFA Support**: Whether to enable 2FA/MFA (default: false)
- **Social Login**: OAuth providers (Google, GitHub, etc.)
- **Session Storage**: Redis, in-memory, etc. (if using sessions)
- **Refresh Token**: Whether to use (default: true)

### Input Example

```
Build a user authentication system:
- Auth method: JWT
- Framework: Express.js + TypeScript
- Database: PostgreSQL
- MFA: Google Authenticator support
- Social login: Google, GitHub
- Refresh Token: enabled
```

## Instructions

Specifies the step-by-step task sequence to follow precisely.

### Step 1: Design the Data Model

Design the database schema for users and authentication.

**Tasks**:
- Design the User table (id, email, password_hash, role, created_at, updated_at)
- RefreshToken table (optional)
- OAuthProvider table (if using social login)
- Never store passwords in plaintext (bcrypt/argon2 hashing is mandatory)

**Example** (PostgreSQL):
```sql
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255),  -- NULL if OAuth only
    role VARCHAR(50) DEFAULT 'user',
    is_verified BOOLEAN DEFAULT false,
    mfa_secret VARCHAR(255),
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE refresh_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    token VARCHAR(500) UNIQUE NOT NULL,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);
```

### Step 2: Implement Password Security

Implement password hashing and verification logic.

**Tasks**:
- Use bcrypt (Node.js) or argon2 (Python)
- Set salt rounds to a minimum of 10
- Password strength validation (minimum 8 chars, upper/lowercase, numbers, special characters)

**Decision Criteria**:
- Node.js projects → use the bcrypt library
- Python projects → use argon2-cffi or passlib
- Performance-critical cases → choose bcrypt
- Cases requiring maximum security → choose argon2

**Example** (Node.js + TypeScript):
```typescript
import bcrypt from 'bcrypt';

const SALT_ROUNDS = 12;

export async function hashPassword(password: string): Promise<string> {
    // Validate password strength
    if (password.length < 8) {
        throw new Error('Password must be at least 8 characters');
    }

    const hasUpperCase = /[A-Z]/.test(password);
    const hasLowerCase = /[a-z]/.test(password);
    const hasNumber = /\d/.test(password);
    const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(password);

    if (!hasUpperCase || !hasLowerCase || !hasNumber || !hasSpecial) {
        throw new Error('Password must contain uppercase, lowercase, number, and special character');
    }

    return await bcrypt.hash(password, SALT_ROUNDS);
}

export async function verifyPassword(password: string, hash: string): Promise<boolean> {
    return await bcrypt.compare(password, hash);
}
```

### Step 3: Generate and Verify JWT Tokens

Implement a token system for JWT-based authentication.

**Tasks**:
- Access Token (short expiry: 15 minutes)
- Refresh Token (long expiry: 7–30 days)
- Use a strong SECRET key for JWT signing (manage via environment variables)
- Include only the minimum necessary information in the token payload (user_id, role)

**Example** (Node.js):
```typescript
import jwt from 'jsonwebtoken';

const ACCESS_TOKEN_SECRET = process.env.ACCESS_TOKEN_SECRET!;
const REFRESH_TOKEN_SECRET = process.env.REFRESH_TOKEN_SECRET!;
const ACCESS_TOKEN_EXPIRY = '15m';
const REFRESH_TOKEN_EXPIRY = '7d';

interface TokenPayload {
    userId: string;
    email: string;
    role: string;
}

export function generateAccessToken(payload: TokenPayload): string {
    return jwt.sign(payload, ACCESS_TOKEN_SECRET, {
        expiresIn: ACCESS_TOKEN_EXPIRY,
        issuer: 'your-app-name',
        audience: 'your-app-users'
    });
}

export function generateRefreshToken(payload: TokenPayload): string {
    return jwt.sign(payload, REFRESH_TOKEN_SECRET, {
        expiresIn: REFRESH_TOKEN_EXPIRY,
        issuer: 'your-app-name',
        audience: 'your-app-users'
    });
}

export function verifyAccessToken(token: string): TokenPayload {
    return jwt.verify(token, ACCESS_TOKEN_SECRET, {
        issuer: 'your-app-name',
        audience: 'your-app-users'
    }) as TokenPayload;
}

export function verifyRefreshToken(token: string): TokenPayload {
    return jwt.verify(token, REFRESH_TOKEN_SECRET, {
        issuer: 'your-app-name',
        audience: 'your-app-users'
    }) as TokenPayload;
}
```

### Step 4: Implement Authentication Middleware

Write authentication middleware to protect API requests.

**Checklist**:
- [x] Extract Bearer token from the Authorization header
- [x] Verify token and check expiry
- [x] Attach user info to req.user for valid tokens
- [x] Error handling (401 Unauthorized)

**Example** (Express.js):
```typescript
import { Request, Response, NextFunction } from 'express';
import { verifyAccessToken } from './jwt';

export interface AuthRequest extends Request {
    user?: {
        userId: string;
        email: string;
        role: string;
    };
}

export function authenticateToken(req: AuthRequest, res: Response, next: NextFunction) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN

    if (!token) {
        return res.status(401).json({ error: 'Access token required' });
    }

    try {
        const payload = verifyAccessToken(token);
        req.user = payload;
        next();
    } catch (error) {
        if (error.name === 'TokenExpiredError') {
            return res.status(401).json({ error: 'Token expired' });
        }
        return res.status(403).json({ error: 'Invalid token' });
    }
}

// Role-based authorization middleware
export function requireRole(...roles: string[]) {
    return (req: AuthRequest, res: Response, next: NextFunction) => {
        if (!req.user) {
            return res.status(401).json({ error: 'Authentication required' });
        }

        if (!roles.includes(req.user.role)) {
            return res.status(403).json({ error: 'Insufficient permissions' });
        }

        next();
    };
}
```

### Step 5: Implement Authentication API Endpoints

Write APIs for registration, login, token refresh, etc.

**Tasks**:
- POST /auth/register - registration
- POST /auth/login - login
- POST /auth/refresh - token refresh
- POST /auth/logout - logout
- GET /auth/me - current user info

**Example**:
```typescript
import express from 'express';
import { hashPassword, verifyPassword } from './password';
import { generateAccessToken, generateRefreshToken, verifyRefreshToken } from './jwt';
import { authenticateToken } from './middleware';

const router = express.Router();

// Registration
router.post('/register', async (req, res) => {
    try {
        const { email, password } = req.body;

        // Check for duplicate email
        const existingUser = await db.user.findUnique({ where: { email } });
        if (existingUser) {
            return res.status(409).json({ error: 'Email already exists' });
        }

        // Hash the password
        const passwordHash = await hashPassword(password);

        // Create the user
        const user = await db.user.create({
            data: { email, password_hash: passwordHash, role: 'user' }
        });

        // Generate tokens
        const accessToken = generateAccessToken({
            userId: user.id,
            email: user.email,
            role: user.role
        });
        const refreshToken = generateRefreshToken({
            userId: user.id,
            email: user.email,
            role: user.role
        });

        // Store Refresh token in DB
        await db.refreshToken.create({
            data: {
                user_id: user.id,
                token: refreshToken,
                expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7 days
            }
        });

        res.status(201).json({
            user: { id: user.id, email: user.email, role: user.role },
            accessToken,
            refreshToken
        });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// Login
router.post('/login', async (req, res) => {
    try {
        const { email, password } = req.body;

        // Find the user
        const user = await db.user.findUnique({ where: { email } });
        if (!user || !user.password_hash) {
            return res.status(401).json({ error: 'Invalid credentials' });
        }

        // Verify the password
        const isValid = await verifyPassword(password, user.password_hash);
        if (!isValid) {
            return res.status(401).json({ error: 'Invalid credentials' });
        }

        // Generate tokens
        const accessToken = generateAccessToken({
            userId: user.id,
            email: user.email,
            role: user.role
        });
        const refreshToken = generateRefreshToken({
            userId: user.id,
            email: user.email,
            role: user.role
        });

        // Store Refresh token
        await db.refreshToken.create({
            data: {
                user_id: user.id,
                token: refreshToken,
                expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
            }
        });

        res.json({
            user: { id: user.id, email: user.email, role: user.role },
            accessToken,
            refreshToken
        });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// Token refresh
router.post('/refresh', async (req, res) => {
    try {
        const { refreshToken } = req.body;

        if (!refreshToken) {
            return res.status(401).json({ error: 'Refresh token required' });
        }

        // Verify Refresh token
        const payload = verifyRefreshToken(refreshToken);

        // Check token in DB
        const storedToken = await db.refreshToken.findUnique({
            where: { token: refreshToken }
        });

        if (!storedToken || storedToken.expires_at < new Date()) {
            return res.status(403).json({ error: 'Invalid or expired refresh token' });
        }

        // Generate new Access token
        const accessToken = generateAccessToken({
            userId: payload.userId,
            email: payload.email,
            role: payload.role
        });

        res.json({ accessToken });
    } catch (error) {
        res.status(403).json({ error: 'Invalid refresh token' });
    }
});

// Current user info
router.get('/me', authenticateToken, async (req: AuthRequest, res) => {
    try {
        const user = await db.user.findUnique({
            where: { id: req.user!.userId },
            select: { id: true, email: true, role: true, created_at: true }
        });

        res.json({ user });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

export default router;
```

## Output format

Defines the exact format that deliverables should follow.

### Basic Structure

```
Project directory/
├── src/
│   ├── auth/
│   │   ├── password.ts          # password hashing/verification
│   │   ├── jwt.ts                # JWT token generation/verification
│   │   ├── middleware.ts         # authentication middleware
│   │   └── routes.ts             # authentication API endpoints
│   ├── models/
│   │   └── User.ts               # user model
│   └── database/
│       └── schema.sql            # database schema
├── .env.example                  # environment variable template
└── README.md                     # authentication system documentation
```

### Environment Variable File (.env.example)

```bash
# JWT Secrets (MUST change in production)
ACCESS_TOKEN_SECRET=your-access-token-secret-min-32-characters
REFRESH_TOKEN_SECRET=your-refresh-token-secret-min-32-characters

# Database
DATABASE_URL=postgresql://user:password@localhost:5432/myapp

# OAuth (Optional)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
```

## Constraints

Specifies mandatory rules and prohibited actions.

### Mandatory Rules (MUST)

1. **Password Security**: Never store passwords in plaintext
   - Use a proven hashing algorithm such as bcrypt or argon2
   - Salt rounds minimum of 10

2. **Environment Variable Management**: Manage all secret keys via environment variables
   - Add .env files to .gitignore
   - Provide a list of required variables via .env.example

3. **Token Expiry**: Access Tokens should be short-lived (15 min), Refresh Tokens appropriately longer (7 days)
   - Balance security and user experience
   - Store Refresh Tokens in the DB to enable revocation

### Prohibited Actions (MUST NOT)

1. **Plaintext Passwords**: Never store passwords in plaintext or print them to logs
   - Serious security risk
   - Legal liability issues

2. **Hardcoding JWT SECRET**: Do not write SECRET keys directly in code
   - Risk of being exposed on GitHub
   - Production security vulnerability

3. **Sensitive Data in Tokens**: Do not include passwords, card numbers, or other sensitive data in JWT payloads
   - JWT can be decoded (it is not encrypted)
   - Include only the minimum information (user_id, role)

### Security Rules

- **Rate Limiting**: Apply rate limiting to the login API (prevents brute-force attacks)
- **HTTPS Required**: Use HTTPS only in production environments
- **CORS Configuration**: Allow only approved domains to access the API
- **Input Validation**: Validate all user input (prevents SQL Injection and XSS)

## Examples

Demonstrates how to apply the skill through real-world use cases.

### Example 1: Express.js + PostgreSQL JWT Authentication

**Situation**: Adding JWT-based user authentication to a Node.js Express app

**User Request**:
```
Add JWT authentication to an Express.js app using PostgreSQL,
with access token expiry of 15 minutes and refresh token expiry of 7 days.
```

**Skill Application Process**:

1. Install packages:
   ```bash
   npm install jsonwebtoken bcrypt pg
   npm install --save-dev @types/jsonwebtoken @types/bcrypt
   ```

2. Create the database schema (use the SQL above)

3. Set environment variables:
   ```bash
   ACCESS_TOKEN_SECRET=$(openssl rand -base64 32)
   REFRESH_TOKEN_SECRET=$(openssl rand -base64 32)
   ```

4. Implement auth modules (use the code examples above)

5. Connect API routes:
   ```typescript
   import authRoutes from './auth/routes';
   app.use('/api/auth', authRoutes);
   ```

**Final Result**: JWT-based authentication system complete, registration/login/token-refresh APIs working

### Example 2: Role-Based Access Control (RBAC)

**Situation**: A permission system that distinguishes administrators from regular users

**User Request**:
```
Create an API accessible only to administrators.
Regular users should receive a 403 error.
```

**Final Result**:
```typescript
// Admin-only API
router.delete('/users/:id',
    authenticateToken,           // verify authentication
    requireRole('admin'),         // verify role
    async (req, res) => {
        // user deletion logic
        await db.user.delete({ where: { id: req.params.id } });
        res.json({ message: 'User deleted' });
    }
);

// Usage example
// Regular user (role: 'user') request → 403 Forbidden
// Admin (role: 'admin') request → 200 OK
```

## Best practices

Recommendations for using this skill effectively.

### Quality Improvement

1. **Password Rotation Policy**: Recommend periodic password changes
   - Change notification every 90 days
   - Prevent reuse of the last 5 passwords
   - Balance user experience and security

2. **Multi-Factor Authentication (MFA)**: Apply 2FA to important accounts
   - Use TOTP apps such as Google Authenticator or Authy
   - SMS is less secure (risk of SIM swapping)
   - Provide backup codes

3. **Audit Logging**: Log all authentication events
   - Record login success/failure, IP address, and User Agent
   - Anomaly detection and post-incident analysis
   - GDPR compliance (exclude sensitive data)

### Efficiency Improvements

- **Token Blacklist**: Revoke Refresh Tokens on logout
- **Redis Caching**: Cache frequently used user data
- **Database Indexing**: Add indexes on email and refresh_token

## Common Issues

Common problems and their solutions.

### Issue 1: "JsonWebTokenError: invalid signature"

**Symptom**:
- Error occurs during token verification
- Login succeeds but authenticated API calls fail

**Cause**:
The SECRET keys for Access Token and Refresh Token are different,
but the same key is being used to verify both.

**Solution**:
1. Check environment variables: `ACCESS_TOKEN_SECRET`, `REFRESH_TOKEN_SECRET`
2. Use the correct SECRET for each token type
3. Verify that environment variables load correctly (initialize `dotenv`)

### Issue 2: Frontend Cannot Log In Due to CORS Error

**Symptom**: "CORS policy" error in the browser console

**Cause**: Missing CORS configuration on the Express server

**Solution**:
```typescript
import cors from 'cors';

app.use(cors({
    origin: process.env.FRONTEND_URL || 'http://localhost:3000',
    credentials: true
}));
```

### Issue 3: Refresh Token Keeps Expiring

**Symptom**: Users are frequently logged out

**Cause**: Refresh Token is not properly managed in the DB

**Solution**:
1. Confirm Refresh Token is saved to DB upon creation
2. Set an appropriate expiry time (minimum 7 days)
3. Add a cron job to regularly clean up expired tokens

## References

### Official Documentation
- [JWT.io - JSON Web Token Introduction](https://jwt.io/introduction)
- [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
- [OAuth 2.0 RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749)

### Libraries
- [jsonwebtoken (Node.js)](https://github.com/auth0/node-jsonwebtoken)
- [bcrypt (Node.js)](https://github.com/kelektiv/node.bcrypt.js)
- [Passport.js](http://www.passportjs.org/) - multiple authentication strategies
- [NextAuth.js](https://next-auth.js.org/) - Next.js authentication

### Security Guides
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [NIST Digital Identity Guidelines](https://pages.nist.gov/800-63-3/)

## Metadata

### Version
- **Current Version**: 1.0.0
- **Last Updated**: 2025-01-01
- **Compatible Platforms**: Claude, ChatGPT, Gemini

### Related Skills
- [api-design](../api-design/SKILL.md): API endpoint design
- [security](../../infrastructure/security/SKILL.md): Security best practices

### Tags
`#authentication` `#authorization` `#JWT` `#OAuth` `#security` `#backend`


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### ../api-design/SKILL.md

```markdown
---
name: api-design
description: Design RESTful and GraphQL APIs following best practices. Use when creating new APIs, refactoring existing endpoints, or documenting API specifications. Handles OpenAPI, REST, GraphQL, versioning.
license: Apache-2.0
compatibility: ""
metadata:
  version: 1.0.0
  author: Agent Skills Team
  tags: api-design, REST, GraphQL, OpenAPI, versioning, backend
  platforms: Claude, ChatGPT, Gemini
---


# API Design

## When to use this skill
- Designing new REST APIs
- Creating GraphQL schemas
- Refactoring API endpoints
- Documenting API specifications
- API versioning strategies
- Defining data models and relationships

## Instructions

### Step 1: Define API requirements
- Identify resources and entities
- Define relationships between entities
- Specify operations (CRUD, custom actions)
- Plan authentication/authorization
- Consider pagination, filtering, sorting

### Step 2: Design REST API

**Resource naming**:
- Use nouns, not verbs: `/users` not `/getUsers`
- Use plural names: `/users/{id}`
- Nest resources logically: `/users/{id}/posts`
- Keep URLs short and intuitive

**HTTP methods**:
- `GET`: Retrieve resources (idempotent)
- `POST`: Create new resources
- `PUT`: Replace entire resource
- `PATCH`: Partial update
- `DELETE`: Remove resources (idempotent)

**Response codes**:
- `200 OK`: Success with response body
- `201 Created`: Resource created successfully
- `204 No Content`: Success with no response body
- `400 Bad Request`: Invalid input
- `401 Unauthorized`: Authentication required
- `403 Forbidden`: No permission
- `404 Not Found`: Resource doesn't exist
- `409 Conflict`: Resource conflict
- `422 Unprocessable Entity`: Validation failed
- `500 Internal Server Error`: Server error

**Example REST endpoint**:
```
GET    /api/v1/users           # List users
GET    /api/v1/users/{id}      # Get user
POST   /api/v1/users           # Create user
PUT    /api/v1/users/{id}      # Update user
PATCH  /api/v1/users/{id}      # Partial update
DELETE /api/v1/users/{id}      # Delete user
```

### Step 3: Request/Response format

**Request example**:
```json
POST /api/v1/users
Content-Type: application/json

{
  "name": "John Doe",
  "email": "[email protected]",
  "role": "admin"
}
```

**Response example**:
```json
HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/v1/users/123

{
  "id": 123,
  "name": "John Doe",
  "email": "[email protected]",
  "role": "admin",
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}
```

### Step 4: Error handling

**Error response format**:
```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input provided",
    "details": [
      {
        "field": "email",
        "message": "Invalid email format"
      }
    ]
  }
}
```

### Step 5: Pagination

**Query parameters**:
```
GET /api/v1/users?page=2&limit=20&sort=-created_at&filter=role:admin
```

**Response with pagination**:
```json
{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 100,
    "pages": 5
  },
  "links": {
    "self": "/api/v1/users?page=2&limit=20",
    "first": "/api/v1/users?page=1&limit=20",
    "prev": "/api/v1/users?page=1&limit=20",
    "next": "/api/v1/users?page=3&limit=20",
    "last": "/api/v1/users?page=5&limit=20"
  }
}
```

### Step 6: Authentication

**Options**:
- JWT (JSON Web Tokens)
- OAuth 2.0
- API Keys
- Session-based

**Example with JWT**:
```
GET /api/v1/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

### Step 7: Versioning

**URL versioning** (recommended):
```
/api/v1/users
/api/v2/users
```

**Header versioning**:
```
GET /api/users
Accept: application/vnd.api+json; version=1
```

### Step 8: Documentation

Create OpenAPI 3.0 specification:

```yaml
openapi: 3.0.0
info:
  title: User Management API
  version: 1.0.0
  description: API for managing users
servers:
  - url: https://api.example.com/v1
paths:
  /users:
    get:
      summary: List users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
    post:
      summary: Create user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreate'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string
          format: email
        created_at:
          type: string
          format: date-time
    UserCreate:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
        email:
          type: string
          format: email
```

## Best practices

1. **Consistency**: Use consistent naming, structure, and patterns
2. **Versioning**: Always version your APIs from the start
3. **Security**: Implement authentication and authorization
4. **Validation**: Validate all inputs on the server side
5. **Rate limiting**: Protect against abuse
6. **Caching**: Use ETags and Cache-Control headers
7. **CORS**: Configure properly for web clients
8. **Documentation**: Keep docs up-to-date with code
9. **Testing**: Test all endpoints thoroughly
10. **Monitoring**: Log requests and track performance

## Common patterns

**Filtering**:
```
GET /api/v1/users?role=admin&status=active
```

**Sorting**:
```
GET /api/v1/users?sort=-created_at,name
```

**Field selection**:
```
GET /api/v1/users?fields=id,name,email
```

**Batch operations**:
```
POST /api/v1/users/batch
{
  "operations": [
    {"action": "create", "data": {...}},
    {"action": "update", "id": 123, "data": {...}}
  ]
}
```

## GraphQL alternative

If REST doesn't fit, consider GraphQL:

```graphql
type User {
  id: ID!
  name: String!
  email: String!
  posts: [Post!]!
  createdAt: DateTime!
}

type Query {
  users(page: Int, limit: Int): [User!]!
  user(id: ID!): User
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!
}
```

## References

- [OpenAPI Specification](https://swagger.io/specification/)
- [REST API Tutorial](https://restfulapi.net/)
- [GraphQL Best Practices](https://graphql.org/learn/best-practices/)
- [HTTP Status Codes](https://httpstatuses.com/)

## Examples

### Example 1: Basic usage
<!-- Add example content here -->

### Example 2: Advanced usage
<!-- Add advanced example content here -->

```

authentication-setup | SkillHub