96 lines
3.4 KiB
Erlang
96 lines
3.4 KiB
Erlang
%%%-------------------------------------------------------------------
|
||
%%% @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.
|