feat: logout
All checks were successful
Build and Deploy Go App / build (push) Successful in 5m51s
Build and Deploy Go App / deploy (push) Successful in 40s

This commit is contained in:
nihonium 2025-12-06 07:01:38 +03:00
parent 714ef57027
commit 69eacd7240
Signed by: nihonium
GPG key ID: 0251623741027CFC
3 changed files with 94 additions and 0 deletions

View file

@ -56,6 +56,9 @@ type ServerInterface interface {
// Get service impersontaion token
// (POST /get-impersonation-token)
GetImpersonationToken(c *gin.Context)
// Logs out the user
// (POST /logout)
Logout(c *gin.Context)
// Refreshes access_token and refresh_token
// (GET /refresh-tokens)
RefreshTokens(c *gin.Context)
@ -91,6 +94,19 @@ func (siw *ServerInterfaceWrapper) GetImpersonationToken(c *gin.Context) {
siw.Handler.GetImpersonationToken(c)
}
// Logout operation middleware
func (siw *ServerInterfaceWrapper) Logout(c *gin.Context) {
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
if c.IsAborted() {
return
}
}
siw.Handler.Logout(c)
}
// RefreshTokens operation middleware
func (siw *ServerInterfaceWrapper) RefreshTokens(c *gin.Context) {
@ -158,6 +174,7 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options
}
router.POST(options.BaseURL+"/get-impersonation-token", wrapper.GetImpersonationToken)
router.POST(options.BaseURL+"/logout", wrapper.Logout)
router.GET(options.BaseURL+"/refresh-tokens", wrapper.RefreshTokens)
router.POST(options.BaseURL+"/sign-in", wrapper.PostSignIn)
router.POST(options.BaseURL+"/sign-up", wrapper.PostSignUp)
@ -199,6 +216,28 @@ func (response GetImpersonationToken401Response) VisitGetImpersonationTokenRespo
return nil
}
type LogoutRequestObject struct {
}
type LogoutResponseObject interface {
VisitLogoutResponse(w http.ResponseWriter) error
}
type Logout200Response struct {
}
func (response Logout200Response) VisitLogoutResponse(w http.ResponseWriter) error {
w.WriteHeader(200)
return nil
}
type Logout500Response = ServerErrorResponse
func (response Logout500Response) VisitLogoutResponse(w http.ResponseWriter) error {
w.WriteHeader(500)
return nil
}
type RefreshTokensRequestObject struct {
}
@ -286,6 +325,9 @@ type StrictServerInterface interface {
// Get service impersontaion token
// (POST /get-impersonation-token)
GetImpersonationToken(ctx context.Context, request GetImpersonationTokenRequestObject) (GetImpersonationTokenResponseObject, error)
// Logs out the user
// (POST /logout)
Logout(ctx context.Context, request LogoutRequestObject) (LogoutResponseObject, error)
// Refreshes access_token and refresh_token
// (GET /refresh-tokens)
RefreshTokens(ctx context.Context, request RefreshTokensRequestObject) (RefreshTokensResponseObject, error)
@ -342,6 +384,31 @@ func (sh *strictHandler) GetImpersonationToken(ctx *gin.Context) {
}
}
// Logout operation middleware
func (sh *strictHandler) Logout(ctx *gin.Context) {
var request LogoutRequestObject
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.Logout(ctx, request.(LogoutRequestObject))
}
for _, middleware := range sh.middlewares {
handler = middleware(handler, "Logout")
}
response, err := handler(ctx, request)
if err != nil {
ctx.Error(err)
ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(LogoutResponseObject); ok {
if err := validResponse.VisitLogoutResponse(ctx.Writer); err != nil {
ctx.Error(err)
}
} else if response != nil {
ctx.Error(fmt.Errorf("unexpected response type: %T", response))
}
}
// RefreshTokens operation middleware
func (sh *strictHandler) RefreshTokens(ctx *gin.Context) {
var request RefreshTokensRequestObject

View file

@ -132,6 +132,17 @@ paths:
"500":
$ref: '#/components/responses/ServerError'
/logout:
post:
summary: Logs out the user
operationId: logout
tags: [Auth]
responses:
"200":
description: Logout success
"500":
$ref: '#/components/responses/ServerError'
components:
securitySchemes:
bearerAuth:

View file

@ -284,6 +284,22 @@ func (s Server) RefreshTokens(ctx context.Context, req auth.RefreshTokensRequest
return auth.RefreshTokens200Response{}, nil
}
func (s Server) Logout(ctx context.Context, req auth.LogoutRequestObject) (auth.LogoutResponseObject, error) {
// TODO: get current tokens and add them to block list
ginCtx, ok := ctx.Value(gin.ContextKey).(*gin.Context)
if !ok {
log.Print("failed to get gin context")
return auth.Logout500Response{}, fmt.Errorf("failed to get gin.Context from context.Context")
}
// Delete cookies by setting MaxAge negative
ginCtx.SetCookie("access_token", "", -1, "/api", "", true, true)
ginCtx.SetCookie("refresh_token", "", -1, "/auth", "", true, true)
ginCtx.SetCookie("xsrf_token", "", -1, "/", "", false, false)
return auth.Logout200Response{}, nil
}
func ExtractBearerToken(header string) (string, error) {
const prefix = "Bearer "
if len(header) <= len(prefix) || header[:len(prefix)] != prefix {