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:
@@ -15,9 +15,10 @@ import (
|
||||
|
||||
// AuthHandler handles authentication endpoints
|
||||
type AuthHandler struct {
|
||||
authService *services.AuthService
|
||||
emailService *services.EmailService
|
||||
cache *services.CacheService
|
||||
authService *services.AuthService
|
||||
emailService *services.EmailService
|
||||
cache *services.CacheService
|
||||
appleAuthService *services.AppleAuthService
|
||||
}
|
||||
|
||||
// NewAuthHandler creates a new auth handler
|
||||
@@ -29,6 +30,11 @@ func NewAuthHandler(authService *services.AuthService, emailService *services.Em
|
||||
}
|
||||
}
|
||||
|
||||
// SetAppleAuthService sets the Apple auth service (called after initialization)
|
||||
func (h *AuthHandler) SetAppleAuthService(appleAuth *services.AppleAuthService) {
|
||||
h.appleAuthService = appleAuth
|
||||
}
|
||||
|
||||
// Login handles POST /api/auth/login/
|
||||
func (h *AuthHandler) Login(c *gin.Context) {
|
||||
var req requests.LoginRequest
|
||||
@@ -362,3 +368,43 @@ func (h *AuthHandler) ResetPassword(c *gin.Context) {
|
||||
Message: "Password reset successfully. Please log in with your new password.",
|
||||
})
|
||||
}
|
||||
|
||||
// AppleSignIn handles POST /api/auth/apple-sign-in/
|
||||
func (h *AuthHandler) AppleSignIn(c *gin.Context) {
|
||||
var req requests.AppleSignInRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, responses.ErrorResponse{
|
||||
Error: "Invalid request body",
|
||||
Details: map[string]string{
|
||||
"validation": err.Error(),
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if h.appleAuthService == nil {
|
||||
log.Error().Msg("Apple auth service not configured")
|
||||
c.JSON(http.StatusInternalServerError, responses.ErrorResponse{
|
||||
Error: "Apple Sign In is not configured",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.authService.AppleSignIn(c.Request.Context(), h.appleAuthService, &req)
|
||||
if err != nil {
|
||||
status := http.StatusUnauthorized
|
||||
message := "Apple Sign In failed"
|
||||
|
||||
if errors.Is(err, services.ErrUserInactive) {
|
||||
message = "Account is inactive"
|
||||
} else if errors.Is(err, services.ErrAppleSignInFailed) {
|
||||
message = "Invalid Apple identity token"
|
||||
}
|
||||
|
||||
log.Debug().Err(err).Msg("Apple Sign In failed")
|
||||
c.JSON(status, responses.ErrorResponse{Error: message})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user