%%%------------------------------------------------------------------- %% @doc Validate extracted authorization token by validating it as a JWT token. %% %% This middleware should be used together with %% {@link oidcc_cowboy_extract_authorization}. %% %%

Usage

%% %% ``` %% OidccCowboyOpts = #{ %% provider => openid_confi_provider_name, %% client_id => <<"client_id">>, %% client_secret => <<"client_secret">> %% }, %% Dispatch = cowboy_router:compile([ %% {'_', [ %% %% ... %% ]} %% ]), %% {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{ %% middlewares => [ %% oidcc_cowboy_extract_authorization, %% oidcc_cowboy_validate_jwt_token, %% cowboy_router, %% cowboy_handler %% ], %% env => #{ %% dispatch => Dispatch, %% oidcc_cowboy_validate_jwt_token => OidccCowboyOpts %% } %% }) %% ''' %% @end %% @since 2.0.0 %%%------------------------------------------------------------------- -module(oidcc_cowboy_validate_jwt_token). -feature(maybe_expr, enable). -behaviour(cowboy_middleware). -export([execute/2]). -export_type([opts/0]). -type opts() :: #{ provider := gen_server:server_ref(), client_id := binary(), client_secret := binary(), send_inactive_token_response => fun( (Req :: cowboy_req:req(), Env :: cowboy_middleware:env()) -> {ok, cowboy_req:req(), cowboy_middleware:env()} | {stop, cowboy_req:req()} ) }. %% Options for the middleware %% %%

Options

%% %% %% @private execute(#{oidcc_cowboy_extract_authorization := undefined} = Req, #{?MODULE := _Opts} = Env) -> {ok, maps:put(?MODULE, undefined, Req), Env}; execute(#{oidcc_cowboy_extract_authorization := Token} = Req, #{?MODULE := Opts} = Env) -> Provider = maps:get(provider, Opts), ClientId = maps:get(client_id, Opts), ClientSecret = maps:get(client_secret, Opts), SendInactiveTokenResponse = maps:get( send_inactive_token_response, Opts, fun send_inactive_token_response/2 ), maybe {ok, ClientContext} ?= oidcc_client_context:from_configuration_worker(Provider, ClientId, ClientSecret), {ok, Claims} ?= oidcc_token:validate_id_token(Token, ClientContext, any), {ok, maps:put(?MODULE, Claims, Req), Env} else {error, token_expired} -> SendInactiveTokenResponse(maps:put(?MODULE, undefined, Req), Env); {error, Reason} -> erlang:error(Reason) end; execute(#{oidcc_cowboy_extract_authorization := _Token} = _Req, #{} = _Env) -> erlang:error(no_config_provided); execute(#{} = _Req, #{?MODULE := _Opts} = _Env) -> erlang:error(no_oidcc_cowboy_extract_authorization). send_inactive_token_response(Req0, _Env) -> Req = cowboy_req:reply( 401, #{<<"content-type">> => <<"text/plain">>}, <<"The provided token is inactive">>, Req0 ), {stop, Req}.