diff --git a/server/docs/docs.go b/server/docs/docs.go index 47dc923..e2a6464 100644 --- a/server/docs/docs.go +++ b/server/docs/docs.go @@ -23,7 +23,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Get system-wide statistics as an admin", @@ -55,7 +55,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the list of all users", @@ -88,7 +88,7 @@ const docTemplate = `{ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Create a new user as an admin", @@ -146,7 +146,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Get a specific user as an admin", @@ -191,7 +191,7 @@ const docTemplate = `{ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Update a specific user as an admin", @@ -254,7 +254,7 @@ const docTemplate = `{ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Delete a specific user as an admin", @@ -307,7 +307,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "List all workspaces and their stats as an admin", @@ -340,7 +340,7 @@ const docTemplate = `{ }, "/auth/login": { "post": { - "description": "Logs in a user", + "description": "Logs in a user and returns a session with access and refresh tokens", "consumes": [ "application/json" ], @@ -351,7 +351,6 @@ const docTemplate = `{ "auth" ], "summary": "Login", - "operationId": "login", "parameters": [ { "description": "Login request", @@ -368,6 +367,12 @@ const docTemplate = `{ "description": "OK", "schema": { "$ref": "#/definitions/handlers.LoginResponse" + }, + "headers": { + "X-CSRF-Token": { + "type": "string", + "description": "CSRF token for future requests" + } } }, "400": { @@ -383,7 +388,7 @@ const docTemplate = `{ } }, "500": { - "description": "Failed to create session", + "description": "Failed to generate CSRF token", "schema": { "$ref": "#/definitions/handlers.ErrorResponse" } @@ -393,11 +398,6 @@ const docTemplate = `{ }, "/auth/logout": { "post": { - "security": [ - { - "BearerAuth": [] - } - ], "description": "Log out invalidates the user's session", "tags": [ "auth" @@ -427,7 +427,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the current authenticated user", @@ -469,22 +469,14 @@ const docTemplate = `{ ], "summary": "Refresh token", "operationId": "refreshToken", - "parameters": [ - { - "description": "Refresh request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RefreshRequest" - } - } - ], "responses": { "200": { "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.RefreshResponse" + "headers": { + "X-CSRF-Token": { + "type": "string", + "description": "New CSRF token" + } } }, "400": { @@ -498,6 +490,12 @@ const docTemplate = `{ "schema": { "$ref": "#/definitions/handlers.ErrorResponse" } + }, + "500": { + "description": "Failed to generate CSRF token", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } } } } @@ -506,7 +504,7 @@ const docTemplate = `{ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the user's profile", @@ -574,7 +572,7 @@ const docTemplate = `{ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Deletes the user's account and all associated data", @@ -641,7 +639,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Lists all workspaces for the current user", @@ -674,7 +672,7 @@ const docTemplate = `{ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Creates a new workspace", @@ -726,7 +724,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the name of the last opened workspace", @@ -756,7 +754,7 @@ const docTemplate = `{ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the name of the last opened workspace", @@ -794,7 +792,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the current workspace", @@ -833,7 +831,7 @@ const docTemplate = `{ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the current workspace", @@ -890,7 +888,7 @@ const docTemplate = `{ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Deletes the current workspace", @@ -937,7 +935,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Lists all files in the user's workspace", @@ -981,7 +979,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the path of the last opened file in the user's workspace", @@ -1026,7 +1024,7 @@ const docTemplate = `{ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the last opened file in the user's workspace", @@ -1088,7 +1086,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the paths of files with the given name in the user's workspace", @@ -1142,7 +1140,7 @@ const docTemplate = `{ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the content of a file in the user's workspace", @@ -1200,7 +1198,7 @@ const docTemplate = `{ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Saves the content of a file in the user's workspace", @@ -1255,7 +1253,7 @@ const docTemplate = `{ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Deletes a file in the user's workspace", @@ -1309,7 +1307,7 @@ const docTemplate = `{ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Stages, commits, and pushes changes to the remote repository", @@ -1365,7 +1363,7 @@ const docTemplate = `{ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Pulls changes from the remote repository", @@ -1493,15 +1491,12 @@ const docTemplate = `{ "handlers.LoginResponse": { "type": "object", "properties": { - "accessToken": { + "expiresAt": { "type": "string" }, - "refreshToken": { + "sessionId": { "type": "string" }, - "session": { - "$ref": "#/definitions/models.Session" - }, "user": { "$ref": "#/definitions/models.User" } @@ -1527,22 +1522,6 @@ const docTemplate = `{ } } }, - "handlers.RefreshRequest": { - "type": "object", - "properties": { - "refreshToken": { - "type": "string" - } - } - }, - "handlers.RefreshResponse": { - "type": "object", - "properties": { - "accessToken": { - "type": "string" - } - } - }, "handlers.SaveFileResponse": { "type": "object", "properties": { @@ -1646,31 +1625,6 @@ const docTemplate = `{ } } }, - "models.Session": { - "type": "object", - "properties": { - "createdAt": { - "description": "When this session was created", - "type": "string" - }, - "expiresAt": { - "description": "When this session expires", - "type": "string" - }, - "id": { - "description": "Unique session identifier", - "type": "string" - }, - "refreshToken": { - "description": "The refresh token associated with this session", - "type": "string" - }, - "userID": { - "description": "ID of the user this session belongs to", - "type": "integer" - } - } - }, "models.User": { "type": "object", "required": [ @@ -1807,6 +1761,13 @@ const docTemplate = `{ } } } + }, + "securityDefinitions": { + "CookieAuth": { + "type": "apiKey", + "name": "access_token", + "in": "cookie" + } } }` diff --git a/server/docs/swagger.json b/server/docs/swagger.json index 52ca878..9f7b36c 100644 --- a/server/docs/swagger.json +++ b/server/docs/swagger.json @@ -16,7 +16,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Get system-wide statistics as an admin", @@ -48,7 +48,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the list of all users", @@ -81,7 +81,7 @@ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Create a new user as an admin", @@ -139,7 +139,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Get a specific user as an admin", @@ -184,7 +184,7 @@ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Update a specific user as an admin", @@ -247,7 +247,7 @@ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Delete a specific user as an admin", @@ -300,7 +300,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "List all workspaces and their stats as an admin", @@ -333,7 +333,7 @@ }, "/auth/login": { "post": { - "description": "Logs in a user", + "description": "Logs in a user and returns a session with access and refresh tokens", "consumes": [ "application/json" ], @@ -344,7 +344,6 @@ "auth" ], "summary": "Login", - "operationId": "login", "parameters": [ { "description": "Login request", @@ -361,6 +360,12 @@ "description": "OK", "schema": { "$ref": "#/definitions/handlers.LoginResponse" + }, + "headers": { + "X-CSRF-Token": { + "type": "string", + "description": "CSRF token for future requests" + } } }, "400": { @@ -376,7 +381,7 @@ } }, "500": { - "description": "Failed to create session", + "description": "Failed to generate CSRF token", "schema": { "$ref": "#/definitions/handlers.ErrorResponse" } @@ -386,11 +391,6 @@ }, "/auth/logout": { "post": { - "security": [ - { - "BearerAuth": [] - } - ], "description": "Log out invalidates the user's session", "tags": [ "auth" @@ -420,7 +420,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the current authenticated user", @@ -462,22 +462,14 @@ ], "summary": "Refresh token", "operationId": "refreshToken", - "parameters": [ - { - "description": "Refresh request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RefreshRequest" - } - } - ], "responses": { "200": { "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.RefreshResponse" + "headers": { + "X-CSRF-Token": { + "type": "string", + "description": "New CSRF token" + } } }, "400": { @@ -491,6 +483,12 @@ "schema": { "$ref": "#/definitions/handlers.ErrorResponse" } + }, + "500": { + "description": "Failed to generate CSRF token", + "schema": { + "$ref": "#/definitions/handlers.ErrorResponse" + } } } } @@ -499,7 +497,7 @@ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the user's profile", @@ -567,7 +565,7 @@ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Deletes the user's account and all associated data", @@ -634,7 +632,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Lists all workspaces for the current user", @@ -667,7 +665,7 @@ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Creates a new workspace", @@ -719,7 +717,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the name of the last opened workspace", @@ -749,7 +747,7 @@ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the name of the last opened workspace", @@ -787,7 +785,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the current workspace", @@ -826,7 +824,7 @@ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the current workspace", @@ -883,7 +881,7 @@ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Deletes the current workspace", @@ -930,7 +928,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Lists all files in the user's workspace", @@ -974,7 +972,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the path of the last opened file in the user's workspace", @@ -1019,7 +1017,7 @@ "put": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Updates the last opened file in the user's workspace", @@ -1081,7 +1079,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the paths of files with the given name in the user's workspace", @@ -1135,7 +1133,7 @@ "get": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Returns the content of a file in the user's workspace", @@ -1193,7 +1191,7 @@ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Saves the content of a file in the user's workspace", @@ -1248,7 +1246,7 @@ "delete": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Deletes a file in the user's workspace", @@ -1302,7 +1300,7 @@ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Stages, commits, and pushes changes to the remote repository", @@ -1358,7 +1356,7 @@ "post": { "security": [ { - "BearerAuth": [] + "CookieAuth": [] } ], "description": "Pulls changes from the remote repository", @@ -1486,15 +1484,12 @@ "handlers.LoginResponse": { "type": "object", "properties": { - "accessToken": { + "expiresAt": { "type": "string" }, - "refreshToken": { + "sessionId": { "type": "string" }, - "session": { - "$ref": "#/definitions/models.Session" - }, "user": { "$ref": "#/definitions/models.User" } @@ -1520,22 +1515,6 @@ } } }, - "handlers.RefreshRequest": { - "type": "object", - "properties": { - "refreshToken": { - "type": "string" - } - } - }, - "handlers.RefreshResponse": { - "type": "object", - "properties": { - "accessToken": { - "type": "string" - } - } - }, "handlers.SaveFileResponse": { "type": "object", "properties": { @@ -1639,31 +1618,6 @@ } } }, - "models.Session": { - "type": "object", - "properties": { - "createdAt": { - "description": "When this session was created", - "type": "string" - }, - "expiresAt": { - "description": "When this session expires", - "type": "string" - }, - "id": { - "description": "Unique session identifier", - "type": "string" - }, - "refreshToken": { - "description": "The refresh token associated with this session", - "type": "string" - }, - "userID": { - "description": "ID of the user this session belongs to", - "type": "integer" - } - } - }, "models.User": { "type": "object", "required": [ @@ -1800,5 +1754,12 @@ } } } + }, + "securityDefinitions": { + "CookieAuth": { + "type": "apiKey", + "name": "access_token", + "in": "cookie" + } } } \ No newline at end of file diff --git a/server/docs/swagger.yaml b/server/docs/swagger.yaml index 505cd38..ce00e3a 100644 --- a/server/docs/swagger.yaml +++ b/server/docs/swagger.yaml @@ -57,12 +57,10 @@ definitions: type: object handlers.LoginResponse: properties: - accessToken: + expiresAt: type: string - refreshToken: + sessionId: type: string - session: - $ref: '#/definitions/models.Session' user: $ref: '#/definitions/models.User' type: object @@ -79,16 +77,6 @@ definitions: example: Pulled changes from remote type: string type: object - handlers.RefreshRequest: - properties: - refreshToken: - type: string - type: object - handlers.RefreshResponse: - properties: - accessToken: - type: string - type: object handlers.SaveFileResponse: properties: filePath: @@ -156,24 +144,6 @@ definitions: workspaceName: type: string type: object - models.Session: - properties: - createdAt: - description: When this session was created - type: string - expiresAt: - description: When this session expires - type: string - id: - description: Unique session identifier - type: string - refreshToken: - description: The refresh token associated with this session - type: string - userID: - description: ID of the user this session belongs to - type: integer - type: object models.User: properties: createdAt: @@ -292,7 +262,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Get system statistics tags: - Admin @@ -314,7 +284,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: List all users tags: - Admin @@ -350,7 +320,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Create a new user tags: - Admin @@ -384,7 +354,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Delete a specific user tags: - Admin @@ -413,7 +383,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Get a specific user tags: - Admin @@ -454,7 +424,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Update a specific user tags: - Admin @@ -476,7 +446,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: List all workspaces tags: - Admin @@ -484,8 +454,7 @@ paths: post: consumes: - application/json - description: Logs in a user - operationId: login + description: Logs in a user and returns a session with access and refresh tokens parameters: - description: Login request in: body @@ -498,6 +467,10 @@ paths: responses: "200": description: OK + headers: + X-CSRF-Token: + description: CSRF token for future requests + type: string schema: $ref: '#/definitions/handlers.LoginResponse' "400": @@ -509,7 +482,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' "500": - description: Failed to create session + description: Failed to generate CSRF token schema: $ref: '#/definitions/handlers.ErrorResponse' summary: Login @@ -530,8 +503,6 @@ paths: description: Failed to logout schema: $ref: '#/definitions/handlers.ErrorResponse' - security: - - BearerAuth: [] summary: Logout tags: - auth @@ -551,7 +522,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Get current user tags: - auth @@ -561,20 +532,15 @@ paths: - application/json description: Refreshes the access token using the refresh token operationId: refreshToken - parameters: - - description: Refresh request - in: body - name: body - required: true - schema: - $ref: '#/definitions/handlers.RefreshRequest' produces: - application/json responses: "200": description: OK - schema: - $ref: '#/definitions/handlers.RefreshResponse' + headers: + X-CSRF-Token: + description: New CSRF token + type: string "400": description: Refresh token required schema: @@ -583,6 +549,10 @@ paths: description: Invalid refresh token schema: $ref: '#/definitions/handlers.ErrorResponse' + "500": + description: Failed to generate CSRF token + schema: + $ref: '#/definitions/handlers.ErrorResponse' summary: Refresh token tags: - auth @@ -625,7 +595,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Delete account tags: - users @@ -669,7 +639,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Update profile tags: - users @@ -691,7 +661,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: List workspaces tags: - workspaces @@ -723,7 +693,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Create workspace tags: - workspaces @@ -753,7 +723,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Delete workspace tags: - workspaces @@ -778,7 +748,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Get workspace tags: - workspaces @@ -815,7 +785,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Update workspace tags: - workspaces @@ -843,7 +813,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: List files tags: - files @@ -878,7 +848,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Delete file tags: - files @@ -916,7 +886,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Get file content tags: - files @@ -952,7 +922,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Save file tags: - files @@ -982,7 +952,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Get last opened file tags: - files @@ -1021,7 +991,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Update last opened file tags: - files @@ -1056,7 +1026,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Lookup file by name tags: - files @@ -1092,7 +1062,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Stage, commit, and push changes tags: - git @@ -1118,7 +1088,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Pull changes from remote tags: - git @@ -1138,7 +1108,7 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Get last workspace name tags: - workspaces @@ -1161,8 +1131,13 @@ paths: schema: $ref: '#/definitions/handlers.ErrorResponse' security: - - BearerAuth: [] + - CookieAuth: [] summary: Update last workspace name tags: - workspaces +securityDefinitions: + CookieAuth: + in: cookie + name: access_token + type: apiKey swagger: "2.0" diff --git a/server/internal/handlers/auth_handlers.go b/server/internal/handlers/auth_handlers.go index 8fb2391..2f1cbb2 100644 --- a/server/internal/handlers/auth_handlers.go +++ b/server/internal/handlers/auth_handlers.go @@ -143,7 +143,6 @@ func (h *Handler) Logout(authManager auth.SessionManager, cookieService auth.Coo // @ID refreshToken // @Accept json // @Produce json -// @Param body body RefreshRequest true "Refresh request" // @Success 200 // @Header 200 {string} X-CSRF-Token "New CSRF token" // @Failure 400 {object} ErrorResponse "Refresh token required"