@intentsolutionsio/fullstack-starter-pack 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,422 @@
1
+ ---
2
+ name: auth-setup
3
+ description: >
4
+ Generate authentication boilerplate with JWT, OAuth, and session support
5
+ shortcut: as
6
+ category: backend
7
+ difficulty: intermediate
8
+ estimated_time: 5-10 minutes
9
+ ---
10
+ # Auth Setup
11
+
12
+ Generates complete authentication boilerplate including JWT, OAuth (Google/GitHub), session management, and password reset flows.
13
+
14
+ ## What This Command Does
15
+
16
+ **Generated Auth System:**
17
+ - JWT authentication with refresh tokens
18
+ - OAuth2 (Google, GitHub, Facebook)
19
+ - Password hashing (bcrypt)
20
+ - Email verification
21
+ - Password reset flow
22
+ - Session management
23
+ - Rate limiting on auth endpoints
24
+ - Authentication middleware
25
+
26
+ **Output:** Complete authentication system ready for production
27
+
28
+ **Time:** 5-10 minutes
29
+
30
+ ---
31
+
32
+ ## Usage
33
+
34
+ ```bash
35
+ # Generate full auth system
36
+ /auth-setup jwt
37
+
38
+ # Shortcut
39
+ /as oauth --providers google,github
40
+
41
+ # With specific features
42
+ /as jwt --features email-verification,password-reset,2fa
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Example Output
48
+
49
+ ### **JWT Authentication**
50
+
51
+ **auth.service.ts:**
52
+ ```typescript
53
+ import bcrypt from 'bcrypt'
54
+ import jwt from 'jsonwebtoken'
55
+ import { User } from './models/User'
56
+
57
+ export class AuthService {
58
+ async register(email: string, password: string, name: string) {
59
+ // Check if user exists
60
+ const existing = await User.findOne({ email })
61
+ if (existing) {
62
+ throw new Error('Email already registered')
63
+ }
64
+
65
+ // Hash password
66
+ const hashedPassword = await bcrypt.hash(password, 12)
67
+
68
+ // Create user
69
+ const user = await User.create({
70
+ email,
71
+ password: hashedPassword,
72
+ name,
73
+ emailVerified: false
74
+ })
75
+
76
+ // Generate verification token
77
+ const verificationToken = this.generateToken({ userId: user.id, type: 'verify' }, '24h')
78
+
79
+ // Send verification email (implement sendEmail)
80
+ await this.sendVerificationEmail(email, verificationToken)
81
+
82
+ // Generate auth tokens
83
+ const accessToken = this.generateAccessToken(user)
84
+ const refreshToken = this.generateRefreshToken(user)
85
+
86
+ return {
87
+ user: { id: user.id, email: user.email, name: user.name },
88
+ accessToken,
89
+ refreshToken
90
+ }
91
+ }
92
+
93
+ async login(email: string, password: string) {
94
+ const user = await User.findOne({ email })
95
+ if (!user) {
96
+ throw new Error('Invalid credentials')
97
+ }
98
+
99
+ const validPassword = await bcrypt.compare(password, user.password)
100
+ if (!validPassword) {
101
+ throw new Error('Invalid credentials')
102
+ }
103
+
104
+ if (!user.emailVerified) {
105
+ throw new Error('Please verify your email')
106
+ }
107
+
108
+ const accessToken = this.generateAccessToken(user)
109
+ const refreshToken = this.generateRefreshToken(user)
110
+
111
+ return {
112
+ user: { id: user.id, email: user.email, name: user.name },
113
+ accessToken,
114
+ refreshToken
115
+ }
116
+ }
117
+
118
+ async refreshToken(refreshToken: string) {
119
+ try {
120
+ const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as any
121
+
122
+ const user = await User.findById(decoded.userId)
123
+ if (!user) {
124
+ throw new Error('User not found')
125
+ }
126
+
127
+ const accessToken = this.generateAccessToken(user)
128
+ return { accessToken }
129
+ } catch (error) {
130
+ throw new Error('Invalid refresh token')
131
+ }
132
+ }
133
+
134
+ async verifyEmail(token: string) {
135
+ const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any
136
+
137
+ if (decoded.type !== 'verify') {
138
+ throw new Error('Invalid token type')
139
+ }
140
+
141
+ await User.findByIdAndUpdate(decoded.userId, { emailVerified: true })
142
+ return { message: 'Email verified successfully' }
143
+ }
144
+
145
+ async requestPasswordReset(email: string) {
146
+ const user = await User.findOne({ email })
147
+ if (!user) {
148
+ // Don't reveal if user exists
149
+ return { message: 'If email exists, reset link sent' }
150
+ }
151
+
152
+ const resetToken = this.generateToken({ userId: user.id, type: 'reset' }, '1h')
153
+ await this.sendPasswordResetEmail(email, resetToken)
154
+
155
+ return { message: 'If email exists, reset link sent' }
156
+ }
157
+
158
+ async resetPassword(token: string, newPassword: string) {
159
+ const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any
160
+
161
+ if (decoded.type !== 'reset') {
162
+ throw new Error('Invalid token type')
163
+ }
164
+
165
+ const hashedPassword = await bcrypt.hash(newPassword, 12)
166
+ await User.findByIdAndUpdate(decoded.userId, { password: hashedPassword })
167
+
168
+ return { message: 'Password reset successfully' }
169
+ }
170
+
171
+ private generateAccessToken(user: any) {
172
+ return jwt.sign(
173
+ { userId: user.id, email: user.email },
174
+ process.env.JWT_SECRET!,
175
+ { expiresIn: '15m' }
176
+ )
177
+ }
178
+
179
+ private generateRefreshToken(user: any) {
180
+ return jwt.sign(
181
+ { userId: user.id },
182
+ process.env.JWT_REFRESH_SECRET!,
183
+ { expiresIn: '7d' }
184
+ )
185
+ }
186
+
187
+ private generateToken(payload: any, expiresIn: string) {
188
+ return jwt.sign(payload, process.env.JWT_SECRET!, { expiresIn })
189
+ }
190
+
191
+ private async sendVerificationEmail(email: string, token: string) {
192
+ // Implement with SendGrid, Resend, etc.
193
+ }
194
+
195
+ private async sendPasswordResetEmail(email: string, token: string) {
196
+ // Implement with SendGrid, Resend, etc.
197
+ }
198
+ }
199
+ ```
200
+
201
+ ### **OAuth2 Setup (Google)**
202
+
203
+ **oauth.controller.ts:**
204
+ ```typescript
205
+ import { OAuth2Client } from 'google-auth-library'
206
+
207
+ const googleClient = new OAuth2Client(
208
+ process.env.GOOGLE_CLIENT_ID,
209
+ process.env.GOOGLE_CLIENT_SECRET,
210
+ process.env.GOOGLE_REDIRECT_URI
211
+ )
212
+
213
+ export class OAuthController {
214
+ async googleLogin(req: Request, res: Response) {
215
+ const authUrl = googleClient.generateAuthUrl({
216
+ access_type: 'offline',
217
+ scope: ['profile', 'email']
218
+ })
219
+
220
+ res.redirect(authUrl)
221
+ }
222
+
223
+ async googleCallback(req: Request, res: Response) {
224
+ const { code } = req.query
225
+
226
+ const { tokens } = await googleClient.getToken(code as string)
227
+ googleClient.setCredentials(tokens)
228
+
229
+ const ticket = await googleClient.verifyIdToken({
230
+ idToken: tokens.id_token!,
231
+ audience: process.env.GOOGLE_CLIENT_ID
232
+ })
233
+
234
+ const payload = ticket.getPayload()
235
+ if (!payload) {
236
+ throw new Error('Invalid token')
237
+ }
238
+
239
+ // Find or create user
240
+ let user = await User.findOne({ email: payload.email })
241
+
242
+ if (!user) {
243
+ user = await User.create({
244
+ email: payload.email,
245
+ name: payload.name,
246
+ avatar: payload.picture,
247
+ emailVerified: true,
248
+ provider: 'google',
249
+ providerId: payload.sub
250
+ })
251
+ }
252
+
253
+ // Generate tokens
254
+ const accessToken = generateAccessToken(user)
255
+ const refreshToken = generateRefreshToken(user)
256
+
257
+ // Redirect with tokens
258
+ res.redirect(`/auth/success?token=${accessToken}&refresh=${refreshToken}`)
259
+ }
260
+ }
261
+ ```
262
+
263
+ ### **Authentication Middleware**
264
+
265
+ **auth.middleware.ts:**
266
+ ```typescript
267
+ import { Request, Response, NextFunction } from 'express'
268
+ import jwt from 'jsonwebtoken'
269
+
270
+ declare global {
271
+ namespace Express {
272
+ interface Request {
273
+ user?: {
274
+ userId: string
275
+ email: string
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ export async function authenticate(req: Request, res: Response, next: NextFunction) {
282
+ try {
283
+ const authHeader = req.headers.authorization
284
+
285
+ if (!authHeader?.startsWith('Bearer ')) {
286
+ return res.status(401).json({ error: 'No token provided' })
287
+ }
288
+
289
+ const token = authHeader.split(' ')[1]
290
+
291
+ const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any
292
+
293
+ req.user = {
294
+ userId: decoded.userId,
295
+ email: decoded.email
296
+ }
297
+
298
+ next()
299
+ } catch (error) {
300
+ if (error instanceof jwt.TokenExpiredError) {
301
+ return res.status(401).json({ error: 'Token expired' })
302
+ }
303
+ return res.status(401).json({ error: 'Invalid token' })
304
+ }
305
+ }
306
+
307
+ export function authorize(...roles: string[]) {
308
+ return async (req: Request, res: Response, next: NextFunction) => {
309
+ if (!req.user) {
310
+ return res.status(401).json({ error: 'Not authenticated' })
311
+ }
312
+
313
+ const user = await User.findById(req.user.userId)
314
+
315
+ if (!user || !roles.includes(user.role)) {
316
+ return res.status(403).json({ error: 'Insufficient permissions' })
317
+ }
318
+
319
+ next()
320
+ }
321
+ }
322
+ ```
323
+
324
+ ### **Rate Limiting**
325
+
326
+ ```typescript
327
+ import rateLimit from 'express-rate-limit'
328
+
329
+ export const authLimiter = rateLimit({
330
+ windowMs: 15 * 60 * 1000, // 15 minutes
331
+ max: 5, // 5 requests per window
332
+ message: 'Too many login attempts, please try again later',
333
+ standardHeaders: true,
334
+ legacyHeaders: false
335
+ })
336
+
337
+ // Usage
338
+ app.post('/api/auth/login', authLimiter, authController.login)
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Environment Variables
344
+
345
+ ```bash
346
+ # JWT
347
+ JWT_SECRET=your-super-secret-key-min-32-chars
348
+ JWT_REFRESH_SECRET=your-refresh-secret-key
349
+ JWT_EXPIRES_IN=15m
350
+ JWT_REFRESH_EXPIRES_IN=7d
351
+
352
+ # OAuth - Google
353
+ GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
354
+ GOOGLE_CLIENT_SECRET=your-client-secret
355
+ GOOGLE_REDIRECT_URI=http://localhost:3000/api/auth/google/callback
356
+
357
+ # OAuth - GitHub
358
+ GITHUB_CLIENT_ID=your-github-client-id
359
+ GITHUB_CLIENT_SECRET=your-github-client-secret
360
+ GITHUB_REDIRECT_URI=http://localhost:3000/api/auth/github/callback
361
+
362
+ # Email
363
+ SMTP_HOST=smtp.sendgrid.net
364
+ SMTP_PORT=587
365
+ SMTP_USER=apikey
366
+ SMTP_PASSWORD=your-sendgrid-api-key
367
+ FROM_EMAIL=[email protected]
368
+ ```
369
+
370
+ ---
371
+
372
+ ## API Routes
373
+
374
+ ```typescript
375
+ // routes/auth.routes.ts
376
+ import { Router } from 'express'
377
+ import { AuthController } from '../controllers/auth.controller'
378
+ import { authenticate } from '../middleware/auth.middleware'
379
+ import { authLimiter } from '../middleware/rate-limit'
380
+
381
+ const router = Router()
382
+ const authController = new AuthController()
383
+
384
+ // Registration & Login
385
+ router.post('/register', authController.register)
386
+ router.post('/login', authLimiter, authController.login)
387
+ router.post('/refresh', authController.refreshToken)
388
+ router.post('/logout', authenticate, authController.logout)
389
+
390
+ // Email Verification
391
+ router.post('/verify-email', authController.verifyEmail)
392
+ router.post('/resend-verification', authController.resendVerification)
393
+
394
+ // Password Reset
395
+ router.post('/forgot-password', authLimiter, authController.forgotPassword)
396
+ router.post('/reset-password', authController.resetPassword)
397
+
398
+ // OAuth
399
+ router.get('/google', authController.googleLogin)
400
+ router.get('/google/callback', authController.googleCallback)
401
+ router.get('/github', authController.githubLogin)
402
+ router.get('/github/callback', authController.githubCallback)
403
+
404
+ // Profile
405
+ router.get('/me', authenticate, authController.getProfile)
406
+ router.patch('/me', authenticate, authController.updateProfile)
407
+ router.post('/change-password', authenticate, authController.changePassword)
408
+
409
+ export default router
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Related Commands
415
+
416
+ - `/env-config-setup` - Generate environment config
417
+ - `/express-api-scaffold` - Generate Express API
418
+ - `/fastapi-scaffold` - Generate FastAPI
419
+
420
+ ---
421
+
422
+ **Secure authentication. Easy integration. Production-ready.**