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, "/")
}
}