Add Sign in with Apple authentication

- Add AppleSocialAuth model to store Apple ID linkages
- Create AppleAuthService for JWT verification with Apple's public keys
- Add AppleSignIn handler and route (POST /auth/apple-sign-in/)
- Implement account linking (links Apple ID to existing accounts by email)
- Add Redis caching for Apple public keys (24-hour TTL)
- Support private relay emails (@privaterelay.appleid.com)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-11-29 01:17:10 -06:00
parent c7dc56e2d2
commit 409d9716bd
10 changed files with 651 additions and 27 deletions

View File

@@ -92,8 +92,12 @@ func SetupRouter(deps *Dependencies) *gin.Engine {
// Initialize middleware
authMiddleware := middleware.NewAuthMiddleware(deps.DB, deps.Cache)
// Initialize Apple auth service
appleAuthService := services.NewAppleAuthService(deps.Cache, cfg)
// Initialize handlers
authHandler := handlers.NewAuthHandler(authService, deps.EmailService, deps.Cache)
authHandler.SetAppleAuthService(appleAuthService)
userHandler := handlers.NewUserHandler(userService)
residenceHandler := handlers.NewResidenceHandler(residenceService, deps.PDFService, deps.EmailService)
taskHandler := handlers.NewTaskHandler(taskService, deps.StorageService)
@@ -183,6 +187,7 @@ func setupPublicAuthRoutes(api *gin.RouterGroup, authHandler *handlers.AuthHandl
auth.POST("/forgot-password/", authHandler.ForgotPassword)
auth.POST("/verify-reset-code/", authHandler.VerifyResetCode)
auth.POST("/reset-password/", authHandler.ResetPassword)
auth.POST("/apple-sign-in/", authHandler.AppleSignIn)
}
}
@@ -194,7 +199,8 @@ func setupProtectedAuthRoutes(api *gin.RouterGroup, authHandler *handlers.AuthHa
auth.GET("/me/", authHandler.CurrentUser)
auth.PUT("/profile/", authHandler.UpdateProfile)
auth.PATCH("/profile/", authHandler.UpdateProfile)
auth.POST("/verify-email/", authHandler.VerifyEmail)
auth.POST("/verify/", authHandler.VerifyEmail) // Alias for mobile app compatibility
auth.POST("/verify-email/", authHandler.VerifyEmail) // Original route
auth.POST("/resend-verification/", authHandler.ResendVerification)
}
}