{"id":27400180,"url":"https://github.com/dokadev/jwt-web-snippets","last_synced_at":"2026-01-22T23:36:11.799Z","repository":{"id":281306568,"uuid":"944881085","full_name":"DokaDev/jwt-web-snippets","owner":"DokaDev","description":null,"archived":false,"fork":false,"pushed_at":"2025-03-08T06:59:53.000Z","size":0,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-08T07:29:39.307Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DokaDev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-08T06:33:44.000Z","updated_at":"2025-03-08T06:59:56.000Z","dependencies_parsed_at":"2025-03-08T07:39:43.491Z","dependency_job_id":null,"html_url":"https://github.com/DokaDev/jwt-web-snippets","commit_stats":null,"previous_names":["dokadev/jwt-web-snippets"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DokaDev%2Fjwt-web-snippets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DokaDev%2Fjwt-web-snippets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DokaDev%2Fjwt-web-snippets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DokaDev%2Fjwt-web-snippets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DokaDev","download_url":"https://codeload.github.com/DokaDev/jwt-web-snippets/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248814924,"owners_count":21165851,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-14T03:26:38.372Z","updated_at":"2026-01-22T23:36:11.746Z","avatar_url":"https://github.com/DokaDev.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# JWT Authentication System\n\n```bash\ngit clone https://github.com/DokaDev/jwt-web-snippets.git --recurse-submodules\n```\n\nThis project demonstrates a complete JWT (JSON Web Token) authentication system with a Next.js frontend client and a Spring Boot backend server. The system implements secure authentication flows with access tokens and refresh tokens stored in Redis.\n\n## Project Structure\n\nThe project consists of two main components:\n\n1. **auth-service-client**: Next.js frontend client application\n2. **auth-service-test**: Spring Boot backend server application\n\n### System Architecture\n\n```mermaid\ngraph TB\n    subgraph \"Frontend (Next.js)\"\n        A[Auth Context] --\u003e B[API Calls]\n        C[Auth Components] --\u003e A\n        D[Application Pages] --\u003e A\n    end\n    \n    subgraph \"Backend (Spring Boot)\"\n        E[Controllers] --\u003e F[Services]\n        F --\u003e G[Redis Storage]\n    end\n    \n    B \u003c--\u003e E\n```\n\n## Authentication Flow\n\n### Login Flow\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Client as Next.js Client\n    participant Server as Spring Boot Server\n    participant Redis\n    \n    User-\u003e\u003eClient: Enter credentials\n    Client-\u003e\u003eServer: POST /api/auth/login\n    Server-\u003e\u003eServer: Validate credentials\n    Server-\u003e\u003eServer: Generate access token\n    Server-\u003e\u003eServer: Generate refresh token\n    Server-\u003e\u003eRedis: Store refresh token\n    Server-\u003e\u003eClient: Return tokens and user info\n    Client-\u003e\u003eClient: Store tokens in localStorage\n    Client-\u003e\u003eClient: Update auth context\n    Client-\u003e\u003eUser: Redirect to protected page\n```\n\n### Token Refresh Flow\n\n```mermaid\nsequenceDiagram\n    participant Client as Next.js Client\n    participant Server as Spring Boot Server\n    participant Redis\n    \n    Note over Client: Access token expires\n    Client-\u003e\u003eClient: Detect expired token\n    Client-\u003e\u003eServer: POST /api/auth/refresh\n    Server-\u003e\u003eRedis: Validate refresh token\n    Server-\u003e\u003eServer: Generate new access token\n    Server-\u003e\u003eServer: Generate new refresh token\n    Server-\u003e\u003eRedis: Update refresh token\n    Server-\u003e\u003eClient: Return new token pair\n    Client-\u003e\u003eClient: Update stored tokens\n```\n\n### Logout Flow\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Client as Next.js Client\n    participant Server as Spring Boot Server\n    participant Redis\n    \n    User-\u003e\u003eClient: Click logout\n    Client-\u003e\u003eServer: POST /api/auth/logout\n    Server-\u003e\u003eRedis: Delete refresh token\n    Server-\u003e\u003eRedis: Add access token to blacklist\n    Server-\u003e\u003eClient: Confirm logout\n    Client-\u003e\u003eClient: Clear auth state\n    Client-\u003e\u003eUser: Redirect to login page\n```\n\n## Detailed Component Descriptions\n\n### Frontend (auth-service-client)\n\n#### Key Components\n\n1. **AuthContext** (`/app/components/auth/AuthContext.tsx`)\n   - Provides authentication state to the entire application\n   - Manages tokens and user information\n   - Handles automatic token refresh\n   - Implements authentication persistence\n\n2. **Auth Library** (`/app/lib/auth.ts`)\n   - Contains authentication-related utility functions\n   - Implements JWT token handling (decoding, verifying)\n   - Provides API calls for authentication endpoints\n\n3. **Auth Components** (`/app/components/auth/AuthButtons.tsx`)\n   - UI components for login/logout functionality\n   - Login form with validation\n   - Protected route functionality\n\n#### Token Management\n\n- Access tokens are stored in localStorage for persistence\n- Token expiration is checked client-side\n- Automatic refresh mechanism is triggered:\n  - When access token is about to expire (\u003c 10 seconds remaining)\n  - On page refresh if access token is expired but refresh token is valid\n  - When attempting to access a protected resource with expired token\n\n### Backend (auth-service-test)\n\n#### Key Components\n\n1. **Controllers**\n   - `AuthController`: Handles authentication endpoints (login, refresh, verify, logout)\n   - `ApiTestController`: Demonstrates protected API endpoints\n   - `TestController`: Basic test endpoint for server health check\n\n2. **Services**\n   - `AuthService`: Manages user authentication logic\n   - `JwtService`: Handles JWT token operations (generation, validation, blacklisting)\n\n3. **Configuration**\n   - `RedisConfig`: Redis connection configuration\n   - `CorsConfig`: CORS settings for cross-origin requests\n   - `SecurityConfig`: Security rules for endpoint access\n\n4. **Models**\n   - `User`: User information model\n   - `AuthTokens`: Token pair model\n   - `JwtPayload`: JWT token payload structure\n   - `JwtConstants`: JWT configuration constants\n\n#### Token Implementation\n\n- **Access Token**: Short-lived (15 seconds) token for API access\n- **Refresh Token**: Longer-lived (10 minutes) token for obtaining new access tokens\n- Redis is used to:\n  - Store refresh tokens with user ID as key\n  - Maintain a blacklist of revoked access tokens\n  - Enable token revocation during logout\n\n## API Endpoints\n\n### Authentication Endpoints\n\n| Endpoint | Method | Description | Request Body | Response |\n|----------|--------|-------------|--------------|----------|\n| `/api/auth/login` | POST | User login | `{email, password}` | `{user, tokens}` |\n| `/api/auth/refresh` | POST | Refresh tokens | `{refreshToken}` | `{accessToken, refreshToken}` |\n| `/api/auth/verify` | POST | Verify token | `{token}` | `{valid: boolean}` |\n| `/api/auth/logout` | POST | Logout user | `{accessToken, userId}` | `{success: boolean}` |\n| `/api/auth/me` | POST | Get user info | `{token}` | User object |\n\n### Test Endpoints\n\n| Endpoint | Method | Description | Auth Required |\n|----------|--------|-------------|---------------|\n| `/test` | GET | Server health check | No |\n| `/api/public` | GET | Public API test | No |\n| `/api/protected` | GET | Protected API test | Yes |\n| `/api/admin` | GET | Admin-only API test | Yes (admin role) |\n\n## Security Features\n\n1. **Token-based Authentication**: Uses JWT for stateless authentication\n2. **Token Refresh**: Implements sliding session with automatic token refresh\n3. **Token Blacklisting**: Invalidates tokens on logout\n4. **Redis Storage**: External storage for token management\n5. **CORS Configuration**: Restricts cross-origin requests to allowed origins\n\n## Implementation Details\n\n### JWT Token Structure\n\n**Access Token Payload:**\n```json\n{\n  \"sub\": \"userId\",\n  \"email\": \"user@example.com\",\n  \"name\": \"User Name\",\n  \"role\": \"user\",\n  \"iat\": 1646121212,\n  \"exp\": 1646121227\n}\n```\n\n**Refresh Token Payload:**\n```json\n{\n  \"sub\": \"userId\",\n  \"iat\": 1646121212,\n  \"exp\": 1646121812\n}\n```\n\n### Redis Key Structure\n\n- **Refresh Tokens**: `refresh:{userId}`\n- **Blacklisted Tokens**: `blacklist:{tokenSignature}`\n\n## Development Environment Setup\n\n### Prerequisites\n\n- Node.js (v14+)\n- Java 17\n- Redis server\n- Docker (optional, for Redis)\n\n### Running the Backend\n\n```bash\ncd auth-service-test\n./mvnw spring-boot:run\n```\n\n### Running the Frontend\n\n```bash\ncd auth-service-client\nnpm install\nnpm run dev\n```\n\n### Running Redis with Docker\n\n```bash\ndocker run --name redis -p 6379:6379 -d redis\n```\n\n## Testing\n\nA test script is provided to verify token refresh functionality:\n\n```bash\n./test-token-refresh.sh\n```\n\nThis script:\n1. Logs in to get initial tokens\n2. Tests protected API access\n3. Waits for token expiration\n4. Verifies expired token rejection\n5. Tests token refresh\n6. Verifies access with refreshed token\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdokadev%2Fjwt-web-snippets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdokadev%2Fjwt-web-snippets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdokadev%2Fjwt-web-snippets/lists"}