| 🍴 Forks | ||||
Provide a secure, self‑hostable weather backend that developers and teams can trust.
- OAuth 2.0 first — secure by design.
- Pluggable data sources and token stores (Redis / memory).
- Low-latency with caching and sensible defaults for production.
Why choose this project:
- Security: full OAuth flows, introspection, revocation.
- Control: self‑host to avoid vendor limits and protect data.
- Extensible: add scrapers or adapters without touching auth.
- Production-ready: caching, rate limiting, and audit logging.
This project implements a complete OAuth 2.0 system following RFC 6749, RFC 7662 (Token Introspection), and RFC 7009 (Token Revocation).
RFC 7662 compliant token introspection endpoint that validates tokens and returns detailed information.
Request:
curl -X POST http://localhost:5000/oauth/introspect \
-H "Authorization: Basic $(echo -n 'client-id:client-secret' | base64)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=your-access-token"Response for Valid Token:
{
"active": true,
"scope": "read write",
"client_id": "weather-api-client",
"username": "[email protected]",
"token_type": "access_token",
"exp": 1700000000,
"iat": 1699990000,
"sub": "user-123",
"aud": "weather-api",
"iss": "weather-api-oauth",
"jti": "token-uuid",
"nbf": 1699990000,
"user_id": "user-123",
"token_use": "access",
"auth_time": 1699990000,
"permissions": ["read", "write"],
"client_name": "Weather API Client",
"issued_for": "weather-api"
}Response for Invalid/Expired Token:
{
"active": false
}Refresh expired access tokens using refresh tokens.
Request:
curl -X POST http://localhost:5000/oauth/token \
-H "Authorization: Basic $(echo -n 'client-id:client-secret' | base64)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&refresh_token=your-refresh-token"Response:
{
"access_token": "new-access-token",
"refresh_token": "new-refresh-token",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write"
}Get access tokens for service-to-service communication.
Request:
curl -X POST http://localhost:5000/oauth/token \
-H "Authorization: Basic $(echo -n 'client-id:client-secret' | base64)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&scope=read"Revoke access or refresh tokens.
Request:
curl -X POST http://localhost:5000/oauth/revoke \
-H "Authorization: Basic $(echo -n 'client-id:client-secret' | base64)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=token-to-revoke"Issue demo tokens for testing purposes.
Request:
curl -X POST http://localhost:5000/oauth/demo/issue \
-H "Authorization: Basic $(echo -n 'client-id:client-secret' | base64)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "[email protected]&scope=read write"curl -H "Authorization: Basic $(echo -n 'client-id:client-secret' | base64)" \
http://localhost:5000/oauth/introspectcurl -H "Authorization: Bearer your-client-secret" \
-d "client_id=your-client-id" \
http://localhost:5000/oauth/introspectcurl -d "client_id=your-client-id&client_secret=your-client-secret" \
http://localhost:5000/oauth/introspectAll weather API endpoints are protected by OAuth middleware. Include your access token in the Authorization header:
curl -H "Authorization: Bearer your-access-token" \
http://localhost:5000/api/weather/londonconst { requireAuth } = require("./src/middlewares/oauth.middleware");
// Require any valid token
app.get("/protected", requireAuth(), (req, res) => {
res.json({ user: req.user });
});
// Require specific scopes
app.get("/admin", requireAuth(["write"]), (req, res) => {
res.json({ user: req.user });
});const { optionalAuth } = require("./src/middlewares/oauth.middleware");
app.get("/public", optionalAuth, (req, res) => {
if (req.user) {
res.json({ authenticated: true, user: req.user });
} else {
res.json({ authenticated: false });
}
});const { requireValidToken } = require("./src/middlewares/oauth.middleware");
// Uses token introspection for comprehensive validation
app.get("/secure", requireValidToken(["read", "write"]), (req, res) => {
res.json({ user: req.user });
});Set these environment variables for OAuth configuration:
# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key
JWT_ACCESS_TOKEN_EXPIRY=3600
JWT_REFRESH_TOKEN_EXPIRY=604800
# OAuth Client Configuration
OAUTH_CLIENT_ID=your-client-id
OAUTH_CLIENT_SECRET=your-client-secret
# Token Storage
TOKEN_STORAGE=redis # or 'memory'
REDIS_URL=redis://localhost:6379
REDIS_PASSWORD=your-redis-password
# Security
NODE_ENV=production # Enables HTTPS requirement- Token Rotation: Refresh tokens are rotated on each use
- Rate Limiting: Built-in rate limiting for all OAuth endpoints
- HTTPS Enforcement: HTTPS required in production
- Token Revocation: Immediate token invalidation
- Scope Validation: Granular permission checking
- Client Authentication: Multiple authentication methods supported
- Token Caching: Redis-based caching for performance
- Audit Logging: Comprehensive request logging
Weather-API/
├── 📁 .github/ #GitHub configuration
│ ├── 📁 ISSUE_TEMPLATE/ # Issue templates
│ │ ├── bug_report.md
│ │ ├── documentation.md
│ │ ├── feature_request.md
│ │ └── performance.md
│ ├── 📁 workflows/ # GitHub Actions workflows
│ │ ├── bundlewatch.yml
│ │ ├── dependabot.yml
│ │ ├── lint.yml
│ │ ├── performance.yml
│ │ ├── render-build.yml
│ │ ├── security.yml
│ │ ├── test.yml
│ │ └── uptime.yml
│ ├── dependabot.yml
│ └── PULL_REQUEST_TEMPLATE.md
├── 📁 docs/ # Documentation
│ ├── MONITORING.md
│ ├── MOST_IMPORTANT_FOR_DEVELOPERS.md
│ ├── OAUTH.md
│ └── REDIS_CACHE.md
├── 📁 public/ # Frontend assets
│ ├── 📁 admin/ # Admin panel
│ │ ├── cache.html
│ │ ├── dashboard.html
│ │ └── login.html
│ ├── 📁 assets/ # Static assets
│ │ ├── gssoc_logo.png
│ │ └── WeatherBackground.jpg
│ ├── 📁 css/ # Stylesheets
│ │ ├── cache.css
│ │ ├── dashboard.css
│ │ └── login.css
│ ├── 📁 Favicon/ # Favicon files
│ │ └── Favicon.PNG
│ ├── 📁 js/ # JavaScript files
│ │ ├── cache.js
│ │ ├── dashboard.js
│ │ └── login.js
│ ├── fallback.png
│ ├── index.html
│ ├── script.js
│ ├── style.css
│ ├── sw.js
│ ├── theme-manager.js
│ └── themes.css
├── 📁 scripts/ # Utility scripts
│ ├── test-oauth.js
│ └── test-redis.js
├── 📁 src/ # Source code
│ ├── 📁 config/ # Configuration files
│ │ ├── cors.js
│ │ ├── database.js
│ │ ├── env.js
│ │ ├── monitoring.config.js
│ │ └── oauth.js
│ ├── 📁 constants/ # Application constants
│ │ └── selectors.js
│ ├── 📁 controllers/ # Route controllers
│ │ ├── oauth.controller.js
│ │ └── weather.controller.js
│ ├── 📁 database/ # Database configuration
│ │ ├── 📁 migrations/ # Database migrations
│ │ │ ├── 001_initial_schema.js
│ │ │ └── 002_add_oauth_tables.js
│ │ └── init.js
│ ├── 📁 middlewares/ # Express middlewares
│ │ ├── cache.middleware.js
│ │ ├── error.middleware.js
│ │ ├── headers.middleware.js
│ │ ├── logging.middleware.js
│ │ ├── oauth.middleware.js
│ │ └── rateLimiter.middleware.js
│ ├── 📁 routes/ # API routes
│ │ ├── admin.routes.js
│ │ ├── configRoutes.js
│ │ ├── oauth.routes.js
│ │ └── weather.routes.js
│ ├── 📁 services/ # Business logic
│ │ ├── cache.service.js
│ │ ├── cacheWarming.service.js
│ │ ├── email.service.js
│ │ ├── monitoring.service.js
│ │ ├── oauth.service.js
│ │ ├── redis.service.js
│ │ ├── selectorValidation.service.js
│ │ ├── tokenStorage.service.js
│ │ ├── user.service.js
│ │ └── weather.service.js
│ └── 📁 utils/ # Utility functions
│ ├── ip.js
│ ├── logger.js
│ ├── parser.js
│ └── sanitize.js
├── 📁 test/ # Test files
│ ├── monitoring.test.js
│ ├── oauth.test.js
│ ├── server.test.js
│ └── weather.test.js
├── .env.example # Environment variables template
├── .gitignore # Git ignore rules
├── .lighthouserc.js # Lighthouse configuration
├── babel.config.js # Babel configuration
├── Code of Conduct.md # Community guidelines
├── Contributing.md # Contribution guidelines
├── docker-compose.yaml # Docker compose configuration
├── Dockerfile # Docker configuration
├── eslint.config.js # ESLint configuration
├── jest.config.js # Jest configuration
├── jest.setup.js # Jest setup file
├── LICENSE.md # License information
├── MONITORING.md # Monitoring documentation
├── package-lock.json # NPM lock file
├── package.json # NPM package configuration
├── README.md # Project documentation
├── Security.md # Security policy
├── server.js # Main server file
└── THEME_IMPLEMENTATION.md # Theme implementation guide\
Have ideas, feedback, or just want to say hi?
- 🛠️ Open an issue in the repository
To ensure a welcoming and inclusive environment, we have a Code of Conduct that all contributors are expected to follow. In short: Be respectful, be kind, and be collaborative. Please read the full Code of Conduct before participating.
This project is licensed under the MIT License.
Feel free to open issues or discussions if you have any feedback, feature suggestions, or want to collaborate!
| Error Code | HTTP Status | Description |
|---|---|---|
invalid_request |
400 | Missing required parameters |
invalid_client |
401 | Invalid client credentials |
invalid_grant |
400 | Invalid refresh token |
invalid_token |
401 | Invalid or expired token |
insufficient_scope |
403 | Token lacks required scopes |
unsupported_grant_type |
400 | Unsupported grant type |
server_error |
500 | Internal server error |
- Missing env vars → add .env or set required keys (JWT_SECRET, OAUTH_CLIENT_ID/SECRET).
- Server won’t start → check PORT, kill conflicting process, or change port.
- Redis errors → verify REDIS_URL/credentials or set TOKEN_STORAGE=memory for dev.
- Introspection shows inactive → confirm token, client auth method, and clock sync.
- Refresh token failing → ensure you use the latest rotated refresh token.
- CORS or frontend blocks → update allowed origins in src/config/cors.js.
- Tests failing → run with TOKEN_STORAGE=memory, npm install, then npm test.
Run the comprehensive test suite:
npm testThe test suite covers:
- Token introspection for valid, expired, and invalid tokens
- Refresh token flow
- Client credentials flow
- Token revocation
- Middleware behavior
- Security edge cases
- Rate limiting
- Caching: Introspection results are cached for 5 minutes
- Redis: Optional Redis backend for high-performance token storage
- Memory Fallback: Automatic fallback to memory storage if Redis unavailable
- Rate Limiting: Configurable rate limits to prevent abuse
- Set
NODE_ENV=productionto enable HTTPS enforcement - Use strong JWT secrets (256+ bits)
- Configure Redis for token storage
- Set up proper CORS configuration
- Monitor rate limiting and token usage
- Regular security audits and token cleanup
GET /api/weather/:city- Get current weather for a cityGET /api/weather-forecast/:city- Get weather forecast for a city
GET /config- Get API configurationGET /api/version- Get API version
All endpoints require OAuth authentication with appropriate scopes.
- Fork → branch (e.g., feat/…, fix/…, docs/…).
- Code + tests + docs: run npm install, npm test, and lint before committing.
- Commit style: Conventional Commits (feat:, fix:, docs:, test:).
- Open a focused PR with: description, testing steps, and checklist: tests, docs, lint.
- Never commit secrets; use .env.example for config samples.
Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.
This project is licensed under the ISC License - see the LICENSE.md file for details.
|
Gaurav Karakoti
|
We love our contributors! If you'd like to help, please check out our CONTRIBUTE.md file for guidelines.
🚀 Stay Ahead of the Weather – One City at a Time! 🌍☀️🌧️

