From 9392ae6c3f48e6c472d43cb4ee2c8664b54b5bc0 Mon Sep 17 00:00:00 2001 From: Loganathan G P <106108501+logusivam@users.noreply.github.com> Date: Fri, 31 Jul 2026 17:01:14 +0530 Subject: [PATCH 1/3] docs: add security.txt contributing setup readme details pull template and release notes --- .github/pull_request_template.md | 47 +++++++++++++++++++++ CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 52 ++++++++++++++++++++++++ LICENSE | 2 +- README.md | 39 ++++++++++++++---- SECURITY.md | 24 ++++++----- apps/web/public/.well-known/security.txt | 5 +++ release.config.cjs | 40 ++++++++++++++++++ release.md | 21 ++++++++++ 9 files changed, 211 insertions(+), 21 deletions(-) create mode 100644 .github/pull_request_template.md create mode 100644 apps/web/public/.well-known/security.txt create mode 100644 release.config.cjs diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..42f1525 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,47 @@ +## Summary + + + +## Type of Change + +- [ ] Bug fix (non-breaking) +- [ ] New feature (non-breaking) +- [ ] Breaking change (requires version bump + CHANGELOG entry) +- [ ] Refactor (no behaviour change) +- [ ] Documentation update +- [ ] CI / tooling change + +## Security Checklist + + + +- [ ] No secrets, API keys, or credentials added to source +- [ ] Input validation added/updated for new endpoints +- [ ] RBAC permissions verified for new/changed routes +- [ ] Rate limiting considered for new public endpoints +- [ ] Audit log event added for new auth actions +- [ ] Cookie options unchanged (httpOnly, Secure, SameSite) +- [ ] No token data exposed in URLs, logs, or response bodies + +## Testing + +- [ ] Unit tests added / updated +- [ ] Integration tests added / updated +- [ ] All existing tests pass (`npm test`) +- [ ] Coverage threshold maintained (โ‰ฅ80%) + +## Documentation + +- [ ] JSDoc added for public functions / classes +- [ ] `docs/api-reference.md` updated if endpoints changed +- [ ] `docs/rbac-model.md` updated if permissions changed +- [ ] `CHANGELOG.md` entry added (or handled by semantic-release) +- [ ] `.env.example` updated if new env vars added + +## Linked Issues + +Closes # + +## Screenshots / Logs (if UI or behaviour change) + + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 415be76..99e2b0a 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -58,7 +58,7 @@ representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders at **logusivam@gmail.com**. All complaints +reported to the community leaders at **logusivam26@gmail.com**. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 904e9e3..ee255fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,3 +9,55 @@ Thank you for your interest in contributing. - A GitHub account ## Setup + +1. **Clone the Repository** + + ```bash + git clone https://github.com/logusivam/tokenforge.git + cd tokenforge + ``` + +2. **Install Dependencies** This project uses npm workspaces. Run install from + the root: + + ```bash + npm install + ``` + +3. **Start Infrastructure Services** TokenForge requires MongoDB and Redis. Use + Docker Compose to spin them up locally: + + ```bash + npm run docker:up + ``` + +4. **Environment Variables Config** Copy the example environment configuration + files: + - For backend (`apps/api`): Copy `apps/api/.env.example` to `apps/api/.env` + and fill in secrets (e.g. `JWT_PRIVATE_KEY`, `JWT_PUBLIC_KEY`, + `COOKIE_SECRET`, `MONGO_URI`, `REDIS_URL`). + - For frontend (`apps/web`): Copy `apps/web/.env.example` to `apps/web/.env` + and update API endpoints. + +5. **Start Development Servers** Run the full monorepo dev stack (API + Web + app): + + ```bash + npm run dev + ``` + +6. **Running Tests** Run the test suites across all packages: + ```bash + npm run test + ``` + +## Development & Git Workflow + +- **Branch Naming**: Branch out from `dev` using descriptive names like + `feature/oauth-flow` or `bugfix/token-rotation`. +- **Commit Messages**: We enforce Conventional Commits. Use prefix types like + `feat(auth):`, `fix(deps):`, `docs(readme):`, `chore:`, etc. Commits that + violate this will fail hooks. +- **Pull Requests**: Pull requests must target the `dev` branch. CI checks + (linting, typescript compilation, unit/integration tests) must pass + successfully before merging. diff --git a/LICENSE b/LICENSE index b6ab53c..b90f03c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 Dark (logusivam) +Copyright (c) 2026 logusivam vision Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index be713fe..9f46aab 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,10 @@ ## Live Demo -๐Ÿ”— [tokenforge.dev](https://tokenforge.dev) ยท -[API Docs](https://tokenforge-api.railway.app/api/docs) +๐Ÿ”— **Frontend**: +[tokenforge-dev.vercel.app](https://tokenforge-dev.vercel.app) +๐Ÿ”— **API Docs (Swagger)**: +[tokenforge-api-ecix.onrender.com/api/docs](https://tokenforge-api-ecix.onrender.com/api/docs) --- @@ -87,12 +89,33 @@ graph TD ``` tokenforge/ โ”œโ”€โ”€ apps/ -โ”‚ โ”œโ”€โ”€ api/ # TypeScript Express API Backend -โ”‚ โ””โ”€โ”€ web/ # React Vite SPA Frontend -โ”œโ”€โ”€ packages/ # Shared Monorepo Workspaces -โ”œโ”€โ”€ docus/ # Architectural documentation -โ”œโ”€โ”€ docker-compose.yml -โ””โ”€โ”€ package.json +โ”‚ โ”œโ”€โ”€ api/ # TypeScript Express API Backend +โ”‚ โ”‚ โ”œโ”€โ”€ src/ +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ config/ # DB, Redis, Sentry, and Swagger setups +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ middleware/ # Rate limiter, RBAC, Sanitization, Error handler +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ modules/ # Auth, OAuth providers, Users, RBAC, Support, Token modules +โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ shared/ # Constants, custom logger, response utilities +โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ server.ts # Application bootstrap and server entry +โ”‚ โ”‚ โ”œโ”€โ”€ tests/ # Unit & Integration test suites +โ”‚ โ”‚ โ”œโ”€โ”€ package.json +โ”‚ โ”‚ โ””โ”€โ”€ tsconfig.json +โ”‚ โ””โ”€โ”€ web/ # React Vite SPA Frontend +โ”‚ โ”œโ”€โ”€ public/ # Static assets (Favicons, Logo, robots.txt, sitemap.xml, security.txt) +โ”‚ โ”œโ”€โ”€ src/ +โ”‚ โ”‚ โ”œโ”€โ”€ components/ # UI forms, navigation layout, feedback widgets +โ”‚ โ”‚ โ”œโ”€โ”€ hooks/ # React hooks (useAuth, etc.) +โ”‚ โ”‚ โ”œโ”€โ”€ pages/ # Auth, Login, Dashboard, Admin, Profile pages +โ”‚ โ”‚ โ”œโ”€โ”€ router/ # ProtectedRoutes and react-router tree +โ”‚ โ”‚ โ”œโ”€โ”€ services/ # Axios API client handlers +โ”‚ โ”‚ โ”œโ”€โ”€ store/ # Zustand global auth state management +โ”‚ โ”‚ โ””โ”€โ”€ main.tsx # React client entry point +โ”‚ โ”œโ”€โ”€ package.json +โ”‚ โ”œโ”€โ”€ tailwind.config.js +โ”‚ โ””โ”€โ”€ vite.config.ts +โ”œโ”€โ”€ packages/ # Shared Monorepo workspaces / helper utilities +โ”œโ”€โ”€ docus/ # Architecture and system documentation +โ”œโ”€โ”€ docker-compose.yml # Local database orchestrations (MongoDB & Redis) +โ””โ”€โ”€ package.json # Monorepo workspace configuration ``` diff --git a/SECURITY.md b/SECURITY.md index 0256c0f..889dfe4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,10 +2,10 @@ ## Supported Versions -| Version | Supported | -|---|---| -| Latest (`main`) | โœ… | -| Older tags | โŒ No backport patches | +| Version | Supported | +| --------------- | ---------------------- | +| Latest (`main`) | โœ… | +| Older tags | โŒ No backport patches | ## Reporting a Vulnerability @@ -15,21 +15,22 @@ 2. Click **"Report a vulnerability"** 3. Fill in the template -Send details to: **security@tokenforge.dev** +Send details to: **devbridgeenquirz@gmail.com** PGP key available at: `https://tokenforge.dev/.well-known/security.txt` ## Response Timeline -| Stage | SLA | -|---|---| -| Acknowledgement | 48 hours | -| Severity assessment | 5 business days | +| Stage | SLA | +| ------------------- | ----------------------------------- | +| Acknowledgement | 48 hours | +| Severity assessment | 5 business days | | Fix + patch release | 14 days (critical) / 30 days (high) | -| Public disclosure | 90 days after fix (coordinated) | +| Public disclosure | 90 days after fix (coordinated) | ## Scope In scope for responsible disclosure: + - Authentication bypass - Refresh token theft or reuse bypass - RBAC privilege escalation @@ -39,6 +40,7 @@ In scope for responsible disclosure: - NoSQL injection Out of scope: + - Denial of service via resource exhaustion (no SLA) - Social engineering -- Issues in third-party dependencies (report to upstream) \ No newline at end of file +- Issues in third-party dependencies (report to upstream) diff --git a/apps/web/public/.well-known/security.txt b/apps/web/public/.well-known/security.txt new file mode 100644 index 0000000..ff6e197 --- /dev/null +++ b/apps/web/public/.well-known/security.txt @@ -0,0 +1,5 @@ +Contact: mailto:devbridgeenquirz@gmail.com +Expires: 2027-12-31T23:59:59.000Z +Preferred-Languages: en +Canonical: https://tokenforge.dev/.well-known/security.txt +Policy: https://github.com/logusivam/tokenforge/blob/dev/SECURITY.md diff --git a/release.config.cjs b/release.config.cjs new file mode 100644 index 0000000..48d7cc0 --- /dev/null +++ b/release.config.cjs @@ -0,0 +1,40 @@ +/** + * @type {import('semantic-release').GlobalConfig} + */ +module.exports = { + branches: ['main', { name: 'dev', prerelease: true }], + plugins: [ + [ + '@semantic-release/commit-analyzer', + { + preset: 'conventionalcommits', + releaseRules: [ + { type: 'feat', release: 'minor' }, + { type: 'fix', release: 'patch' }, + { type: 'perf', release: 'patch' }, + { type: 'chore', scope: 'deps', release: 'patch' }, + ], + }, + ], + [ + '@semantic-release/release-notes-generator', + { + preset: 'conventionalcommits', + }, + ], + [ + '@semantic-release/changelog', + { + changelogFile: 'CHANGELOG.md', + }, + ], + [ + '@semantic-release/git', + { + assets: ['package.json', 'package-lock.json', 'CHANGELOG.md'], + message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', + }, + ], + '@semantic-release/github', + ], +} diff --git a/release.md b/release.md index 8a329f9..b31d8d0 100644 --- a/release.md +++ b/release.md @@ -35,3 +35,24 @@ If a container build fails or fails to pass health status verifications: 2. **Railway Engine Fallback**: Integrates zero-downtime healthcheck checks. If dynamic healthchecks fail (`/api/v1/health`), Railway rolls back to the previous stable build image automatically. + +--- + +## ๐Ÿค– Automated Releases via Semantic Release + +Releases are fully automated via `semantic-release` on push/merge to `main` and +`dev` branches. + +### How it Works: + +1. **Analyze Commits**: Commits are parsed using Conventional Commits rules: + - `feat(...)` -> Bumps **Minor** version. + - `fix(...)` or `perf(...)` -> Bumps **Patch** version. + - Commits containing `BREAKING CHANGE:` -> Bumps **Major** version. +2. **Generate Notes**: Release notes are generated from the commit history. +3. **Update Changelog**: `CHANGELOG.md` is updated automatically. +4. **Push Release Commit**: The updated `package.json`, `package-lock.json`, and + `CHANGELOG.md` are committed back to Git (prefixed with `chore(release):` and + containing `[skip ci]` to prevent build loops). +5. **Publish Tag & GitHub Release**: A new git tag is created, and a release + with changelog details is published on GitHub. From d82829c77be08eaaad54de0ee934bd819e59b62b Mon Sep 17 00:00:00 2001 From: Loganathan G P <106108501+logusivam@users.noreply.github.com> Date: Fri, 31 Jul 2026 17:39:00 +0530 Subject: [PATCH 2/3] fix(docs): update security.txt PGP link and define API docs paths in swagger.ts --- SECURITY.md | 3 +- apps/api/src/config/swagger.ts | 293 ++++++++++++++++++++--- apps/web/public/.well-known/security.txt | 2 +- 3 files changed, 265 insertions(+), 33 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 889dfe4..6e33643 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,7 +16,8 @@ 3. Fill in the template Send details to: **devbridgeenquirz@gmail.com** -PGP key available at: `https://tokenforge.dev/.well-known/security.txt` +PGP key available at: +`https://tokenforge-dev.vercel.app/.well-known/security.txt` ## Response Timeline diff --git a/apps/api/src/config/swagger.ts b/apps/api/src/config/swagger.ts index df69b54..3fcd712 100644 --- a/apps/api/src/config/swagger.ts +++ b/apps/api/src/config/swagger.ts @@ -6,24 +6,36 @@ const swaggerDocument = { info: { title: 'TokenForge API', version: '1.0.0', - description: 'JWT auth system with refresh token rotation, OAuth2 PKCE, and RBAC', - contact: { name: 'Dark', url: 'https://tokenforge.dev' }, + description: + 'Stateless, high-performance JWT authentication engine with Refresh Token Rotation, OAuth2 PKCE, and RBAC - built from scratch.', + contact: { + name: 'TokenForge Security', + email: 'devbridgeenquirz@gmail.com', + url: 'https://tokenforge-dev.vercel.app', + }, license: { name: 'MIT', url: 'https://opensource.org/licenses/MIT' }, }, - servers: [ - { url: 'http://localhost:3000/api/v1', description: 'Local development' }, - { url: 'https://tokenforge-api.railway.app/api/v1', description: 'Production' }, - ], + servers: [{ url: '/api/v1', description: 'API v1 Root' }], components: { securitySchemes: { BearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT', - description: 'RS256-signed JWT access token (15 min expiry)', + description: + 'RS256-signed JWT access token (15 min expiry). Passed in Authorization header: Bearer ', }, }, schemas: { + RegisterRequest: { + type: 'object', + required: ['email', 'password', 'name'], + properties: { + name: { type: 'string', example: 'Jane Doe' }, + email: { type: 'string', format: 'email', example: 'jane@example.com' }, + password: { type: 'string', minLength: 8, example: 'SuperSecure123!' }, + }, + }, LoginRequest: { type: 'object', required: ['email', 'password'], @@ -32,19 +44,61 @@ const swaggerDocument = { password: { type: 'string', minLength: 8, example: 'Secure123!' }, }, }, - AuthResponse: { + UpdateProfileRequest: { type: 'object', properties: { - accessToken: { type: 'string', description: 'RS256 JWT โ€” store in memory only' }, - user: { - type: 'object', - properties: { - id: { type: 'string' }, - name: { type: 'string' }, - email: { type: 'string' }, - role: { type: 'string', enum: ['admin', 'moderator', 'user', 'guest'] }, - }, + name: { type: 'string', example: 'Jane Smith' }, + avatar: { + type: 'string', + description: 'URL or base64 Data URI', + example: 'https://avatar.url/image.png', + }, + password: { type: 'string', minLength: 8 }, + oldPassword: { type: 'string' }, + }, + }, + UserObject: { + type: 'object', + properties: { + id: { type: 'string', example: '65c9e2b172a1e002fa88cd1a' }, + name: { type: 'string', example: 'Jane Doe' }, + email: { type: 'string', format: 'email', example: 'jane@example.com' }, + role: { type: 'string', enum: ['admin', 'moderator', 'user', 'guest'], example: 'user' }, + avatar: { type: 'string', example: 'https://avatar.url/image.png' }, + providers: { + type: 'array', + items: { type: 'string' }, + example: ['google'], }, + createdAt: { type: 'string', format: 'date-time' }, + }, + }, + AuthResponse: { + type: 'object', + properties: { + accessToken: { type: 'string', description: 'Short-lived JWT (store in-memory only)' }, + user: { $ref: '#/components/schemas/UserObject' }, + }, + }, + AuditLogObject: { + type: 'object', + properties: { + id: { type: 'string' }, + userId: { type: 'string' }, + action: { type: 'string', example: 'auth:login' }, + status: { type: 'string', enum: ['success', 'failure'] }, + ip: { type: 'string', example: '127.0.0.1' }, + userAgent: { type: 'string' }, + details: { type: 'object' }, + timestamp: { type: 'string', format: 'date-time' }, + }, + }, + StatsResponse: { + type: 'object', + properties: { + totalUsers: { type: 'integer', example: 1250 }, + activeSessions: { type: 'integer', example: 87 }, + registrations24h: { type: 'integer', example: 12 }, }, }, ErrorResponse: { @@ -52,13 +106,35 @@ const swaggerDocument = { properties: { status: { type: 'string', example: 'error' }, statusCode: { type: 'integer', example: 401 }, - message: { type: 'string' }, - requestId: { type: 'string' }, + message: { type: 'string', example: 'Invalid credentials or expired session' }, + requestId: { type: 'string', example: 'req-982ac-912' }, }, }, }, }, paths: { + '/auth/register': { + post: { + tags: ['Authentication'], + summary: 'Register a new user account', + requestBody: { + required: true, + content: { + 'application/json': { schema: { $ref: '#/components/schemas/RegisterRequest' } }, + }, + }, + responses: { + 201: { + description: 'Registration successful - returns access token & user object', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/AuthResponse' } }, + }, + }, + 400: { description: 'Validation error or email already in use' }, + 429: { description: 'Too many registrations from this IP' }, + }, + }, + }, '/auth/login': { post: { tags: ['Authentication'], @@ -71,7 +147,7 @@ const swaggerDocument = { }, responses: { 200: { - description: 'Login successful โ€” refresh token set in httpOnly cookie', + description: 'Login successful - sets secure httpOnly refresh token cookie', content: { 'application/json': { schema: { $ref: '#/components/schemas/AuthResponse' } }, }, @@ -85,11 +161,12 @@ const swaggerDocument = { '/auth/refresh': { post: { tags: ['Authentication'], - summary: 'Refresh access token using httpOnly cookie', - description: 'Rotates refresh token. Old token is invalidated immediately.', + summary: 'Rotate credentials using httpOnly Refresh Token cookie', + description: + 'Exchanges active Refresh Token cookie for a new short-lived Access Token and rotated Refresh Token cookie.', responses: { 200: { - description: 'New access token issued', + description: 'Access token successfully refreshed', content: { 'application/json': { schema: { @@ -99,29 +176,183 @@ const swaggerDocument = { }, }, }, - 401: { description: 'Refresh token invalid, expired, or reuse detected' }, + 401: { + description: + 'Refresh token invalid, expired, or reuse detected (triggers family revocation)', + }, }, }, }, '/auth/logout': { post: { tags: ['Authentication'], - summary: 'Logout โ€” revoke current refresh token + blacklist access token', + summary: 'Invalidate active sessions', security: [{ BearerAuth: [] }], responses: { - 200: { description: 'Logged out successfully' }, - 401: { description: 'Not authenticated' }, + 200: { description: 'Logged out successfully, cookies cleared' }, + 401: { description: 'Unauthorized' }, + }, + }, + }, + '/oauth/google': { + get: { + tags: ['OAuth2 PKCE'], + summary: 'Redirect to Google OAuth2 flow', + responses: { + 302: { description: 'Redirects browser to Google authentication prompt' }, + }, + }, + }, + '/oauth/github': { + get: { + tags: ['OAuth2 PKCE'], + summary: 'Redirect to GitHub OAuth2 flow', + responses: { + 302: { description: 'Redirects browser to GitHub authentication prompt' }, }, }, }, '/users/me': { get: { - tags: ['Users'], - summary: 'Get current user profile', + tags: ['User Management'], + summary: 'Get active profile details', + security: [{ BearerAuth: [] }], + responses: { + 200: { + description: 'Active profile details returned', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/UserObject' } }, + }, + }, + 401: { description: 'Unauthorized' }, + }, + }, + patch: { + tags: ['User Management'], + summary: 'Update user profile details', + security: [{ BearerAuth: [] }], + requestBody: { + required: true, + content: { + 'application/json': { schema: { $ref: '#/components/schemas/UpdateProfileRequest' } }, + }, + }, + responses: { + 200: { + description: 'Profile updated successfully', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/UserObject' } }, + }, + }, + 400: { description: 'Validation error' }, + 401: { description: 'Unauthorized' }, + }, + }, + delete: { + tags: ['User Management'], + summary: 'Self-delete active user account', + security: [{ BearerAuth: [] }], + responses: { + 200: { description: 'Account deleted successfully' }, + 401: { description: 'Unauthorized' }, + }, + }, + }, + '/admin/users': { + get: { + tags: ['Admin Console'], + summary: 'Get listing of registered users', + security: [{ BearerAuth: [] }], + responses: { + 200: { + description: 'List of users returned', + content: { + 'application/json': { + type: 'array', + items: { $ref: '#/components/schemas/UserObject' }, + }, + }, + }, + 401: { description: 'Unauthorized' }, + 403: { description: 'Forbidden - requires users:read or audit:read permissions' }, + }, + }, + }, + '/admin/audit': { + get: { + tags: ['Admin Console'], + summary: 'Get system security audit trail events', + security: [{ BearerAuth: [] }], + responses: { + 200: { + description: 'Audit log listing returned', + content: { + 'application/json': { + type: 'array', + items: { $ref: '#/components/schemas/AuditLogObject' }, + }, + }, + }, + 401: { description: 'Unauthorized' }, + 403: { description: 'Forbidden - requires audit:read permission' }, + }, + }, + }, + '/admin/stats': { + get: { + tags: ['Admin Console'], + summary: 'Get global system activity metrics', + security: [{ BearerAuth: [] }], + responses: { + 200: { + description: 'Metrics returned', + content: { + 'application/json': { schema: { $ref: '#/components/schemas/StatsResponse' } }, + }, + }, + 401: { description: 'Unauthorized' }, + 403: { description: 'Forbidden' }, + }, + }, + }, + '/admin/users/{id}/role': { + patch: { + tags: ['Admin Console'], + summary: 'Change role assignment for a user', + security: [{ BearerAuth: [] }], + parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }], + requestBody: { + required: true, + content: { + 'application/json': { + schema: { + type: 'object', + required: ['role'], + properties: { + role: { type: 'string', enum: ['admin', 'moderator', 'user', 'guest'] }, + }, + }, + }, + }, + }, + responses: { + 200: { description: 'User role updated successfully' }, + 400: { description: 'Validation error' }, + 401: { description: 'Unauthorized' }, + 403: { description: 'Forbidden' }, + }, + }, + }, + '/admin/users/{id}/sessions': { + delete: { + tags: ['Admin Console'], + summary: 'Force revoke all sessions for a user', security: [{ BearerAuth: [] }], + parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }], responses: { - 200: { description: 'User profile object' }, - 401: { description: 'Not authenticated' }, + 200: { description: 'Sessions successfully revoked' }, + 401: { description: 'Unauthorized' }, + 403: { description: 'Forbidden' }, }, }, }, diff --git a/apps/web/public/.well-known/security.txt b/apps/web/public/.well-known/security.txt index ff6e197..095f36e 100644 --- a/apps/web/public/.well-known/security.txt +++ b/apps/web/public/.well-known/security.txt @@ -1,5 +1,5 @@ Contact: mailto:devbridgeenquirz@gmail.com Expires: 2027-12-31T23:59:59.000Z Preferred-Languages: en -Canonical: https://tokenforge.dev/.well-known/security.txt +Canonical: https://tokenforge-dev.vercel.app/.well-known/security.txt Policy: https://github.com/logusivam/tokenforge/blob/dev/SECURITY.md From 55fd36a5e7374f0456003e32fd5d16fe4770ebcf Mon Sep 17 00:00:00 2001 From: Loganathan G P <106108501+logusivam@users.noreply.github.com> Date: Fri, 31 Jul 2026 18:47:27 +0530 Subject: [PATCH 3/3] fix(release): bypass vercel rewrites for static files with extensions --- apps/web/public/.well-known/security.txt | 2 +- apps/web/vercel.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/public/.well-known/security.txt b/apps/web/public/.well-known/security.txt index 095f36e..f968e44 100644 --- a/apps/web/public/.well-known/security.txt +++ b/apps/web/public/.well-known/security.txt @@ -2,4 +2,4 @@ Contact: mailto:devbridgeenquirz@gmail.com Expires: 2027-12-31T23:59:59.000Z Preferred-Languages: en Canonical: https://tokenforge-dev.vercel.app/.well-known/security.txt -Policy: https://github.com/logusivam/tokenforge/blob/dev/SECURITY.md +Policy: https://github.com/logusivam/tokenforge/blob/main/SECURITY.md diff --git a/apps/web/vercel.json b/apps/web/vercel.json index 1323cda..1dcf377 100644 --- a/apps/web/vercel.json +++ b/apps/web/vercel.json @@ -1,7 +1,7 @@ { "rewrites": [ { - "source": "/(.*)", + "source": "/((?!.*\\.).*)", "destination": "/index.html" } ]