%%%------------------------------------------------------------------- %%% @doc Обработчик обновления токена (клиентский API). %%% POST – принимает refresh_token, возвращает новую пару access + refresh токенов. %%% @end %%%------------------------------------------------------------------- -module(handler_refresh). -behaviour(cowboy_handler). -export([init/2]). -export([trails/0]). %%% cowboy_handler callback -spec init(cowboy_req:req(), any()) -> {ok, cowboy_req:req(), any()}. init(Req, _Opts) -> case cowboy_req:method(Req) of <<"POST">> -> refresh(Req); _ -> handler_utils:send_error(Req, 405, <<"Method not allowed">>) end. %%% Swagger metadata -spec trails() -> [map()]. trails() -> [ #{ path => <<"/v1/refresh">>, method => <<"POST">>, description => <<"Refresh user access token using refresh token">>, tags => [<<"Auth">>], requestBody => #{ required => true, content => #{ <<"application/json">> => #{ schema => #{ type => object, required => [<<"refresh_token">>], properties => #{refresh_token => #{type => string}} } } } }, responses => #{ 200 => #{ description => <<"New user token pair (access + refresh)">>, content => #{ <<"application/json">> => #{ schema => token_pair_schema() } } }, 400 => #{description => <<"Missing refresh_token field or invalid JSON">>}, 401 => #{description => <<"Refresh token expired or not found">>} } } ]. token_pair_schema() -> #{ type => object, properties => #{ token => #{type => string, description => <<"JWT access token">>}, refresh_token => #{type => string, description => <<"Refresh token">>} } }. %%%=================================================================== %%% HTTP-методы %%%=================================================================== %% @doc POST /v1/refresh — обновление пользовательского токена. -spec refresh(cowboy_req:req()) -> {ok, binary(), cowboy_req:req()}. refresh(Req) -> {ok, Body, Req1} = cowboy_req:read_body(Req), try jsx:decode(Body, [return_maps]) of #{<<"refresh_token">> := RefreshToken} -> case logic_auth_session:refresh_user(RefreshToken) of {ok, NewToken, NewRefreshToken} -> handler_utils:send_json(Req1, 200, #{ token => NewToken, refresh_token => NewRefreshToken }); {error, reuse_detected} -> handler_utils:send_error(Req1, 401, <<"Refresh token reuse detected">>); {error, not_found} -> handler_utils:send_error(Req1, 401, <<"Refresh token not found">>); {error, expired} -> handler_utils:send_error(Req1, 401, <<"Refresh token expired">>); {error, revoked} -> handler_utils:send_error(Req1, 401, <<"Refresh token revoked">>); {error, _} -> handler_utils:send_error(Req1, 401, <<"Invalid refresh token">>) end; _ -> handler_utils:send_error(Req1, 400, <<"Missing refresh_token field">>) catch _:_ -> handler_utils:send_error(Req1, 400, <<"Invalid JSON">>) end.