package handlers import ( "context" "log" "net/http" "tixe/auth" "tixe/db" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" ) func AuthCallback(auth *auth.Auth) gin.HandlerFunc { return func(c *gin.Context) { session := sessions.Default(c) if c.Query("state") != session.Get("state") { c.String(http.StatusBadRequest, "Invalid state parameter!") return } token, err := auth.Exchange(c.Request.Context(), c.Query("code")) if err != nil { c.String(http.StatusUnauthorized, "Failed to exchange authorization code for token!") return } idToken, err := auth.VerifyIDToken(c.Request.Context(), token) if err != nil { c.String(http.StatusInternalServerError, "Failed to verify ID token!") return } var profile map[string]interface{} if err := idToken.Claims(&profile); err != nil { c.String(http.StatusInternalServerError, err.Error()) return } session.Set("access_token", token.AccessToken) session.Set("profile", profile) if err := session.Save(); err != nil { c.String(http.StatusInternalServerError, err.Error()) return } // Create a user in the database for this OIDC user. // idToken.Subject shooooould be unique and always the same for a user. // I think. Maybe. // But first, check if it exists! var oidcSubject string err = db.PgPool.QueryRow(context.Background(), "SELECT oidc_subject FROM users WHERE oidc_subject = $1", idToken.Subject).Scan(&oidcSubject) if err != nil { log.Printf("[tixe/auth] WARN: Failed to query database for oidc user") c.String(http.StatusInternalServerError, err.Error()) return } if idToken.Subject == oidcSubject { // Exists, we outta here! c.Redirect(http.StatusTemporaryRedirect, "/") return } // Now create it, since it did not exists. _, err = db.PgPool.Exec(context.Background(), "INSERT INTO users(display_name, oidc_subject) VALUES($1, $2)", profile["name"].(string), idToken.Subject) if err != nil { log.Printf("[tixe/auth] WARN: Could not create database entry for oidc user.") c.String(http.StatusInternalServerError, err.Error()) return } c.Redirect(http.StatusTemporaryRedirect, "/") } }