package api import ( "database/sql" "fmt" "net/http" "time" "github.com/gin-gonic/gin" ) type renewAccessRequest struct { RefreshToken string `json:"refresh_token" binding:"required"` } type renewAccessResponse struct { AccesToken string `json:"access_token"` AccessTokenExpiresAt time.Time `json:"access_token_expires_at"` } func (server *Server) renewAccessToken(ctx *gin.Context) { var req renewAccessRequest 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 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(refreshPayload.ExpiredAt) { err := fmt.Errorf("Expired session") ctx.JSON(http.StatusUnauthorized, errorResponse(err, "")) return } user, err := server.store.GetUserByEmail(ctx, refreshPayload.Email) if err != nil { if err == sql.ErrNoRows { ctx.JSON(http.StatusNotFound, errorResponse(err, "")) return } ctx.JSON(http.StatusInternalServerError, errorResponse(err, "")) return } merchant, err := server.store.GetMerchantByUserId(ctx, user.ID) if err != nil { ctx.JSON(http.StatusInternalServerError, errorResponse(err, "")) return } accessToken, accessPayload, err := server.tokenMaker.CreateToken( refreshPayload.Email, merchant.ID.String(), server.config.TokenDuration, ) if err != nil { ctx.JSON(http.StatusInternalServerError, errorResponse(err, "")) return } res := renewAccessResponse{ AccesToken: accessToken, AccessTokenExpiresAt: accessPayload.ExpiredAt, } ctx.JSON(http.StatusOK, res) }