df/bff/api/token.go
2023-10-09 00:25:57 +02:00

90 lines
2.1 KiB
Go

package api
import (
"database/sql"
"errors"
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
type renewAccessTokenRequest struct {
RefreshToken string `json:"refresh_token" binding:"required"`
}
type renewAccessTokenResponse struct {
AccessToken string `json:"access_token"`
AccessTokenExpiresAt time.Time `json:"access_token_expires_at"`
}
func (server *Server) renewAccessToken(ctx *gin.Context) {
var req renewAccessTokenRequest
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
refreshPayload, err := server.tokenMaker.VerifyToken(req.RefreshToken)
if err != nil {
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
return
}
session, err := server.store.GetSession(ctx, refreshPayload.ID)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
ctx.JSON(http.StatusNotFound, errorResponse(err))
return
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
if session.IsBlocked {
err := fmt.Errorf("blocked session")
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
return
}
if session.Email != refreshPayload.Email {
err := fmt.Errorf("incorrect session user")
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
return
}
if session.RefreshToken != req.RefreshToken {
err := fmt.Errorf("mismatched session token")
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
return
}
if time.Now().After(session.ExpiresAt) {
err := fmt.Errorf("expired session")
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
return
}
id, err := server.tokenMaker.NewTokenID()
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(errors.New("failed to create session token")))
}
accessToken, accessPayload, err := server.tokenMaker.CreateToken(
refreshPayload.Email,
id,
server.config.AccessTokenDuration,
)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
rsp := renewAccessTokenResponse{
AccessToken: accessToken,
AccessTokenExpiresAt: accessPayload.ExpiredAt,
}
ctx.JSON(http.StatusOK, rsp)
}