Conversation
prdai
left a comment
There was a problem hiding this comment.
i am not sure if these comments are valid since I do not have much experience with Go, hopefully they make sense, so I am going to add them as comments, thanks
| // AuthMiddleware is a middleware to verify Firebase ID tokens | ||
| func AuthMiddleware() gin.HandlerFunc { | ||
| return func(c *gin.Context) { | ||
| credentialsJSON := os.Getenv("FIREBASE_CREDENTIALS_JSON") |
There was a problem hiding this comment.
would moving the firebase initialization and credential initalization to something like internal/config/firebase.go be better? also as far as I know i think we need to load the credential's json file and then pass it in the initlization?
| } | ||
|
|
||
| // GetUserFromContext retrieves the user from the request context | ||
| func GetUserFromContext(c *gin.Context) *auth.Token { |
There was a problem hiding this comment.
if it retrieves the user shouldn't it return a user object? or its uuid?
There was a problem hiding this comment.
Pull Request Overview
This PR replaces the existing custom GORM-based authentication (including user/session/password-reset) with Firebase Auth, removing legacy routes and middleware and introducing a new /auth/check endpoint backed by Firebase.
- Completely removes old models, handlers, and middleware for user registration, sessions, and password reset.
- Adds
AuthMiddlewareto verify Firebase ID tokens and aCheckAuthhandler for health checks of authenticated users. - Updates application routing and dependencies (adds Firebase and Google API modules, removes DB init, rate limiter, and API key auth).
Reviewed Changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/models/user.go | Removed legacy User model |
| internal/models/session.go | Removed legacy Session model |
| internal/models/password_reset.go | Removed legacy PasswordReset model |
| internal/middleware/ratelimit.go | Removed custom rate limiter middleware |
| internal/middleware/apikey.go | Removed API key auth middleware |
| internal/middleware/auth.go | Added Firebase Auth middleware and GetUserFromContext |
| internal/handlers/auth.go | Removed old auth/register/login handlers, added CheckAuth |
| internal/handlers/password_reset.go | Removed custom password reset handlers |
| internal/config/database.go | Removed database init and migrations |
| go.mod | Added firebase.google.com/go and Google API dependencies |
| application.go | Updated routing to use Firebase, removed DB/rate/APIKey setup |
| .example.env | Updated example env vars for Firebase setup |
Comments suppressed due to low confidence (2)
internal/middleware/auth.go:72
- [nitpick] Consider adding a doc comment for
GetUserFromContextto explain the expected context key and return value, improving clarity for other developers.
func GetUserFromContext(c *gin.Context) *auth.Token {
internal/middleware/auth.go:17
- New middleware should have unit tests covering scenarios like missing header, invalid token, and valid token to ensure correct behavior.
func AuthMiddleware() gin.HandlerFunc {
| // AuthMiddleware is a middleware to verify Firebase ID tokens | ||
| func AuthMiddleware() gin.HandlerFunc { | ||
| return func(c *gin.Context) { | ||
| credentialsJSON := os.Getenv("FIREBASE_CREDENTIALS_JSON") | ||
| if credentialsJSON == "" { | ||
| log.Println("FIREBASE_CREDENTIALS_JSON environment variable not set") | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase credentials not configured"}) | ||
| return | ||
| } | ||
| opt := option.WithCredentialsJSON([]byte(credentialsJSON)) | ||
|
|
||
| projectID := os.Getenv("FIREBASE_PROJECT_ID") | ||
| if projectID == "" { | ||
| log.Println("FIREBASE_PROJECT_ID environment variable not set") | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase project ID not configured"}) | ||
| return | ||
| } | ||
| config := &firebase.Config{ | ||
| ProjectID: projectID, | ||
| } | ||
|
|
||
| app, err := firebase.NewApp(context.Background(), config, opt) | ||
| if err != nil { | ||
| log.Printf("error initializing app: %v\n", err) | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error initializing app"}) | ||
| return | ||
| } | ||
|
|
||
| client, err := app.Auth(context.Background()) | ||
| if err != nil { | ||
| log.Printf("error getting Auth client: %v\n", err) | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error getting Auth client"}) | ||
| return | ||
| } | ||
|
|
||
|
|
There was a problem hiding this comment.
Initializing the Firebase App on every request can add significant latency. Consider initializing the Firebase App and Auth client once (e.g., in an init() function or during application startup) and reusing the client in the middleware.
| // AuthMiddleware is a middleware to verify Firebase ID tokens | |
| func AuthMiddleware() gin.HandlerFunc { | |
| return func(c *gin.Context) { | |
| credentialsJSON := os.Getenv("FIREBASE_CREDENTIALS_JSON") | |
| if credentialsJSON == "" { | |
| log.Println("FIREBASE_CREDENTIALS_JSON environment variable not set") | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase credentials not configured"}) | |
| return | |
| } | |
| opt := option.WithCredentialsJSON([]byte(credentialsJSON)) | |
| projectID := os.Getenv("FIREBASE_PROJECT_ID") | |
| if projectID == "" { | |
| log.Println("FIREBASE_PROJECT_ID environment variable not set") | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase project ID not configured"}) | |
| return | |
| } | |
| config := &firebase.Config{ | |
| ProjectID: projectID, | |
| } | |
| app, err := firebase.NewApp(context.Background(), config, opt) | |
| if err != nil { | |
| log.Printf("error initializing app: %v\n", err) | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error initializing app"}) | |
| return | |
| } | |
| client, err := app.Auth(context.Background()) | |
| if err != nil { | |
| log.Printf("error getting Auth client: %v\n", err) | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error getting Auth client"}) | |
| return | |
| } | |
| var ( | |
| firebaseApp *firebase.App | |
| authClient *auth.Client | |
| ) | |
| func InitFirebase() { | |
| credentialsJSON := os.Getenv("FIREBASE_CREDENTIALS_JSON") | |
| if credentialsJSON == "" { | |
| log.Fatal("FIREBASE_CREDENTIALS_JSON environment variable not set") | |
| } | |
| opt := option.WithCredentialsJSON([]byte(credentialsJSON)) | |
| projectID := os.Getenv("FIREBASE_PROJECT_ID") | |
| if projectID == "" { | |
| log.Fatal("FIREBASE_PROJECT_ID environment variable not set") | |
| } | |
| config := &firebase.Config{ | |
| ProjectID: projectID, | |
| } | |
| var err error | |
| firebaseApp, err = firebase.NewApp(context.Background(), config, opt) | |
| if err != nil { | |
| log.Fatalf("error initializing Firebase app: %v", err) | |
| } | |
| authClient, err = firebaseApp.Auth(context.Background()) | |
| if err != nil { | |
| log.Fatalf("error initializing Auth client: %v", err) | |
| } | |
| } | |
| // AuthMiddleware is a middleware to verify Firebase ID tokens | |
| func AuthMiddleware() gin.HandlerFunc { | |
| return func(c *gin.Context) { |
| // AuthMiddleware is a middleware to verify Firebase ID tokens | ||
| func AuthMiddleware() gin.HandlerFunc { | ||
| return func(c *gin.Context) { | ||
| credentialsJSON := os.Getenv("FIREBASE_CREDENTIALS_JSON") | ||
| if credentialsJSON == "" { | ||
| log.Println("FIREBASE_CREDENTIALS_JSON environment variable not set") | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase credentials not configured"}) | ||
| return | ||
| } | ||
| opt := option.WithCredentialsJSON([]byte(credentialsJSON)) | ||
|
|
||
| projectID := os.Getenv("FIREBASE_PROJECT_ID") | ||
| if projectID == "" { | ||
| log.Println("FIREBASE_PROJECT_ID environment variable not set") | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase project ID not configured"}) | ||
| return | ||
| } | ||
| config := &firebase.Config{ | ||
| ProjectID: projectID, | ||
| } | ||
|
|
||
| app, err := firebase.NewApp(context.Background(), config, opt) | ||
| if err != nil { | ||
| log.Printf("error initializing app: %v\n", err) | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error initializing app"}) | ||
| return | ||
| } | ||
|
|
||
| client, err := app.Auth(context.Background()) | ||
| if err != nil { | ||
| log.Printf("error getting Auth client: %v\n", err) | ||
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error getting Auth client"}) | ||
| return | ||
| } | ||
|
|
||
|
|
There was a problem hiding this comment.
Repeated calls to firebase.NewApp and app.Auth in the middleware can be expensive. Move app and client initialization out of the request handler to improve throughput.
| // AuthMiddleware is a middleware to verify Firebase ID tokens | |
| func AuthMiddleware() gin.HandlerFunc { | |
| return func(c *gin.Context) { | |
| credentialsJSON := os.Getenv("FIREBASE_CREDENTIALS_JSON") | |
| if credentialsJSON == "" { | |
| log.Println("FIREBASE_CREDENTIALS_JSON environment variable not set") | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase credentials not configured"}) | |
| return | |
| } | |
| opt := option.WithCredentialsJSON([]byte(credentialsJSON)) | |
| projectID := os.Getenv("FIREBASE_PROJECT_ID") | |
| if projectID == "" { | |
| log.Println("FIREBASE_PROJECT_ID environment variable not set") | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "Firebase project ID not configured"}) | |
| return | |
| } | |
| config := &firebase.Config{ | |
| ProjectID: projectID, | |
| } | |
| app, err := firebase.NewApp(context.Background(), config, opt) | |
| if err != nil { | |
| log.Printf("error initializing app: %v\n", err) | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error initializing app"}) | |
| return | |
| } | |
| client, err := app.Auth(context.Background()) | |
| if err != nil { | |
| log.Printf("error getting Auth client: %v\n", err) | |
| c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "error getting Auth client"}) | |
| return | |
| } | |
| var ( | |
| authClient *auth.Client | |
| ) | |
| func InitFirebase() { | |
| credentialsJSON := os.Getenv("FIREBASE_CREDENTIALS_JSON") | |
| if credentialsJSON == "" { | |
| log.Fatal("FIREBASE_CREDENTIALS_JSON environment variable not set") | |
| } | |
| opt := option.WithCredentialsJSON([]byte(credentialsJSON)) | |
| projectID := os.Getenv("FIREBASE_PROJECT_ID") | |
| if projectID == "" { | |
| log.Fatal("FIREBASE_PROJECT_ID environment variable not set") | |
| } | |
| config := &firebase.Config{ | |
| ProjectID: projectID, | |
| } | |
| app, err := firebase.NewApp(context.Background(), config, opt) | |
| if err != nil { | |
| log.Fatalf("error initializing app: %v\n", err) | |
| } | |
| client, err := app.Auth(context.Background()) | |
| if err != nil { | |
| log.Fatalf("error getting Auth client: %v\n", err) | |
| } | |
| authClient = client | |
| } | |
| // AuthMiddleware is a middleware to verify Firebase ID tokens | |
| func AuthMiddleware() gin.HandlerFunc { | |
| return func(c *gin.Context) { |
|
|
||
| // Start server | ||
| if err := r.Run(":8080"); err != nil { | ||
| if err := r.Run(":5005"); err != nil { |
There was a problem hiding this comment.
Hardcoding the server port makes it harder to configure in different environments. Consider reading the port from an environment variable with a default fallback.
Scaffold Firebase auth endpoint and middleware
Remove old routes