-module(flwr_oauth2@authorization_grant). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/flwr_oauth2/authorization_grant.gleam"). -export([to_string/1, error_to_string/1, new/0, set_authorization_endpoint/2, set_response_type/2, set_redirect_uri/2, set_client_id/2, set_scope/2, set_state/2, set_code_challenge/3, parse_authorization_response_query/1, parse_authorization_response/1, to_token_request/4, to_token_request_with_pkce_verifier/5, make_redirect_uri/1, random_state/1, random_state32/0]). -export_type([state/0, response_type/0, code_challenge_method/0, authorization_code_grant_request/0, authorization_response/0, parse_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type state() :: {state, binary()}. -type response_type() :: code | token. -type code_challenge_method() :: plain | s256. -type authorization_code_grant_request() :: {authorization_code_grant_request, gleam@uri:uri(), response_type(), gleam@option:option(gleam@uri:uri()), flwr_oauth2:client_id(), list(binary()), gleam@option:option(state()), gleam@option:option(binary()), gleam@option:option(code_challenge_method())}. -type authorization_response() :: {implicit_grant_response, gleam@option:option(state()), flwr_oauth2:access_token_response()} | {code_grant_response, gleam@option:option(state()), binary()} | {error_response, gleam@option:option(state()), binary(), gleam@option:option(binary()), gleam@option:option(gleam@uri:uri())}. -type parse_error() :: {parse_error, gleam@option:option(binary())}. -file("src/flwr_oauth2/authorization_grant.gleam", 73). ?DOC(" Creates a String representation of the AuthorizationResponse\n"). -spec to_string(authorization_response()) -> binary(). to_string(Resp) -> State = begin _pipe = erlang:element(2, Resp), _pipe@1 = gleam@option:map(_pipe, fun(S) -> erlang:element(2, S) end), gleam@option:unwrap(_pipe@1, <<"None"/utf8>>) end, case Resp of {implicit_grant_response, _, Token} -> Token_response = flwr_oauth2:to_string_token_response(Token), <<<<<<<<"ImplicitGrantResponse( token: "/utf8, Token_response/binary>>/binary, ", state: "/utf8>>/binary, State/binary>>/binary, " )"/utf8>>; {code_grant_response, _, Code} -> <<<<<<<<"CodeGrantResponse(code: "/utf8, Code/binary>>/binary, ", state: "/utf8>>/binary, State/binary>>/binary, ")"/utf8>>; {error_response, _, Error, Error_description, Error_uri} -> Error_description@1 = begin _pipe@2 = Error_description, gleam@option:unwrap(_pipe@2, <<"None"/utf8>>) end, Error_uri@1 = begin _pipe@3 = Error_uri, _pipe@4 = gleam@option:map(_pipe@3, fun gleam@uri:to_string/1), gleam@option:unwrap(_pipe@4, <<"None"/utf8>>) end, <<<<<<<<<<<<<<<<"ErrorResponse( error: "/utf8, Error/binary>>/binary, ", error_description: "/utf8>>/binary, Error_description@1/binary>>/binary, ", error_uri: "/utf8>>/binary, Error_uri@1/binary>>/binary, ", state: "/utf8>>/binary, State/binary>>/binary, " )"/utf8>> end. -file("src/flwr_oauth2/authorization_grant.gleam", 103). -spec error_to_string(parse_error()) -> binary(). error_to_string(Error) -> Field = begin _pipe = erlang:element(2, Error), gleam@option:unwrap(_pipe, <<"None"/utf8>>) end, <<<<"ParseError(field: "/utf8, Field/binary>>/binary, ")"/utf8>>. -file("src/flwr_oauth2/authorization_grant.gleam", 110). ?DOC( " Creates a new Authorization Code Grant Request, with empty fields.\n" " Mostly a convenience function, watch out for empty values!\n" ). -spec new() -> authorization_code_grant_request(). new() -> {authorization_code_grant_request, {uri, none, none, none, none, <<""/utf8>>, none, none}, token, none, {client_id, <<""/utf8>>}, [], none, none, none}. -file("src/flwr_oauth2/authorization_grant.gleam", 123). -spec set_authorization_endpoint( authorization_code_grant_request(), gleam@uri:uri() ) -> authorization_code_grant_request(). set_authorization_endpoint(Req, Authorization_endpoint) -> {authorization_code_grant_request, Authorization_endpoint, erlang:element(3, Req), erlang:element(4, Req), erlang:element(5, Req), erlang:element(6, Req), erlang:element(7, Req), erlang:element(8, Req), erlang:element(9, Req)}. -file("src/flwr_oauth2/authorization_grant.gleam", 130). -spec set_response_type(authorization_code_grant_request(), response_type()) -> authorization_code_grant_request(). set_response_type(Req, Response_type) -> {authorization_code_grant_request, erlang:element(2, Req), Response_type, erlang:element(4, Req), erlang:element(5, Req), erlang:element(6, Req), erlang:element(7, Req), erlang:element(8, Req), erlang:element(9, Req)}. -file("src/flwr_oauth2/authorization_grant.gleam", 137). -spec set_redirect_uri(authorization_code_grant_request(), gleam@uri:uri()) -> authorization_code_grant_request(). set_redirect_uri(Req, Redirect_uri) -> {authorization_code_grant_request, erlang:element(2, Req), erlang:element(3, Req), {some, Redirect_uri}, erlang:element(5, Req), erlang:element(6, Req), erlang:element(7, Req), erlang:element(8, Req), erlang:element(9, Req)}. -file("src/flwr_oauth2/authorization_grant.gleam", 144). -spec set_client_id(authorization_code_grant_request(), flwr_oauth2:client_id()) -> authorization_code_grant_request(). set_client_id(Req, Client_id) -> {authorization_code_grant_request, erlang:element(2, Req), erlang:element(3, Req), erlang:element(4, Req), Client_id, erlang:element(6, Req), erlang:element(7, Req), erlang:element(8, Req), erlang:element(9, Req)}. -file("src/flwr_oauth2/authorization_grant.gleam", 148). -spec set_scope(authorization_code_grant_request(), list(binary())) -> authorization_code_grant_request(). set_scope(Req, Scope) -> {authorization_code_grant_request, erlang:element(2, Req), erlang:element(3, Req), erlang:element(4, Req), erlang:element(5, Req), Scope, erlang:element(7, Req), erlang:element(8, Req), erlang:element(9, Req)}. -file("src/flwr_oauth2/authorization_grant.gleam", 152). -spec set_state(authorization_code_grant_request(), state()) -> authorization_code_grant_request(). set_state(Req, State) -> {authorization_code_grant_request, erlang:element(2, Req), erlang:element(3, Req), erlang:element(4, Req), erlang:element(5, Req), erlang:element(6, Req), {some, State}, erlang:element(8, Req), erlang:element(9, Req)}. -file("src/flwr_oauth2/authorization_grant.gleam", 156). -spec set_code_challenge( authorization_code_grant_request(), binary(), code_challenge_method() ) -> authorization_code_grant_request(). set_code_challenge(Req, Code_challenge, Code_challenge_method) -> {authorization_code_grant_request, erlang:element(2, Req), erlang:element(3, Req), erlang:element(4, Req), erlang:element(5, Req), erlang:element(6, Req), erlang:element(7, Req), {some, Code_challenge}, {some, Code_challenge_method}}. -file("src/flwr_oauth2/authorization_grant.gleam", 334). -spec parse_optional_field(gleam@dict:dict(binary(), FQI), binary()) -> gleam@option:option(FQI). parse_optional_field(Query, Key) -> _pipe = Query, _pipe@1 = gleam_stdlib:map_get(_pipe, Key), gleam@option:from_result(_pipe@1). -file("src/flwr_oauth2/authorization_grant.gleam", 343). -spec create_parse_error({ok, FQM} | {error, any()}, binary()) -> {ok, FQM} | {error, parse_error()}. create_parse_error(Res, Field) -> _pipe = Res, gleam@result:replace_error(_pipe, {parse_error, {some, Field}}). -file("src/flwr_oauth2/authorization_grant.gleam", 307). -spec parse_optional_uri( gleam@dict:dict(binary(), binary()), binary(), fun((binary()) -> {ok, FPT} | {error, any()}), fun((gleam@option:option(FPT)) -> FPY) ) -> {ok, FPY} | {error, parse_error()}. parse_optional_uri(Query, Key, Parser, Apply) -> case gleam_stdlib:map_get(Query, Key) of {error, _} -> {ok, Apply(none)}; {ok, Value} -> Value@1 = begin _pipe = Parser(Value), create_parse_error(_pipe, Key) end, gleam@result:'try'( Value@1, fun(Parsed) -> {ok, Apply({some, Parsed})} end ) end. -file("src/flwr_oauth2/authorization_grant.gleam", 290). -spec parse_error_response(gleam@dict:dict(binary(), binary())) -> {ok, gleam@option:option(authorization_response())} | {error, parse_error()}. parse_error_response(Query) -> case gleam_stdlib:map_get(Query, <<"error"/utf8>>) of {ok, Error} -> Error_description = begin _pipe = Query, parse_optional_field(_pipe, <<"error_description"/utf8>>) end, State = begin _pipe@1 = Query, _pipe@2 = parse_optional_field(_pipe@1, <<"state"/utf8>>), gleam@option:map(_pipe@2, fun(Field@0) -> {state, Field@0} end) end, parse_optional_uri( Query, <<"error_uri"/utf8>>, fun gleam_stdlib:uri_parse/1, fun(Error_uri) -> {some, {error_response, State, Error, Error_description, Error_uri}} end ); {error, _} -> {ok, none} end. -file("src/flwr_oauth2/authorization_grant.gleam", 323). -spec parse_required_field( gleam@dict:dict(binary(), FQB), binary(), fun((FQB) -> {ok, FQE} | {error, parse_error()}) ) -> {ok, FQE} | {error, parse_error()}. parse_required_field(Query, Key, Then) -> _pipe = Query, _pipe@1 = gleam_stdlib:map_get(_pipe, Key), _pipe@2 = create_parse_error(_pipe@1, Key), gleam@result:'try'(_pipe@2, Then). -file("src/flwr_oauth2/authorization_grant.gleam", 242). -spec parse_authorization_code_response(gleam@dict:dict(binary(), binary())) -> {ok, authorization_response()} | {error, parse_error()}. parse_authorization_code_response(Query) -> parse_required_field( Query, <<"code"/utf8>>, fun(Code) -> State = begin _pipe = Query, _pipe@1 = parse_optional_field(_pipe, <<"state"/utf8>>), gleam@option:map(_pipe@1, fun(Field@0) -> {state, Field@0} end) end, {ok, {code_grant_response, State, Code}} end ). -file("src/flwr_oauth2/authorization_grant.gleam", 253). -spec parse_authorization_implicit_response(gleam@dict:dict(binary(), binary())) -> {ok, authorization_response()} | {error, parse_error()}. parse_authorization_implicit_response(Query) -> parse_required_field( Query, <<"access_token"/utf8>>, fun(Access_token) -> parse_required_field( Query, <<"token_type"/utf8>>, fun(Token_type) -> Expires_in = begin _pipe = Query, _pipe@1 = parse_optional_field( _pipe, <<"expires_in"/utf8>> ), _pipe@2 = gleam@option:map( _pipe@1, fun gleam_stdlib:parse_int/1 ), _pipe@3 = gleam@option:map( _pipe@2, fun(Res) -> gleam@result:map( Res, fun(Field@0) -> {some, Field@0} end ) end ), _pipe@4 = gleam@option:unwrap(_pipe@3, {ok, none}), create_parse_error(_pipe@4, <<"expires_in"/utf8>>) end, gleam@result:'try'( Expires_in, fun(Expires_in@1) -> Scope = begin _pipe@5 = Query, _pipe@6 = parse_optional_field( _pipe@5, <<"scope"/utf8>> ), _pipe@7 = gleam@option:map( _pipe@6, fun flwr_oauth2:parse_scope/1 ), gleam@option:unwrap(_pipe@7, []) end, State = begin _pipe@8 = Query, _pipe@9 = gleam_stdlib:map_get( _pipe@8, <<"state"/utf8>> ), _pipe@10 = gleam@option:from_result(_pipe@9), gleam@option:map( _pipe@10, fun(Field@0) -> {state, Field@0} end ) end, {ok, {implicit_grant_response, State, {access_token_response, Access_token, Token_type, Expires_in@1, none, Scope}}} end ) end ) end ). -file("src/flwr_oauth2/authorization_grant.gleam", 229). ?DOC( " Parses the query from the authorization response HTTP request.\n" " This function is intended to be used in case your implementation does not use the standard gleam/http/request type.\n" ). -spec parse_authorization_response_query(gleam@dict:dict(binary(), binary())) -> {ok, authorization_response()} | {error, parse_error()}. parse_authorization_response_query(Query) -> Error_response = parse_error_response(Query), gleam@result:'try'( Error_response, fun(Error_response@1) -> Error_response@2 = begin _pipe = Error_response@1, gleam@option:map(_pipe, fun(Field@0) -> {ok, Field@0} end) end, gleam@option:lazy_unwrap( Error_response@2, fun() -> Code_response = parse_authorization_code_response(Query), gleam@result:try_recover( Code_response, fun(_) -> parse_authorization_implicit_response(Query) end ) end ) end ). -file("src/flwr_oauth2/authorization_grant.gleam", 206). ?DOC( " Parses the redirect URI, with the code for the code grant type or the access token for the implicit grant type.\n" " See [Section 4.1.2](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2)\n" ). -spec parse_authorization_response(gleam@http@request:request(any())) -> {ok, authorization_response()} | {error, parse_error()}. parse_authorization_response(Req) -> Query = begin _pipe = erlang:element(9, Req), _pipe@1 = gleam@option:map(_pipe, fun gleam_stdlib:parse_query/1), _pipe@2 = gleam@option:to_result(_pipe@1, nil), _pipe@3 = gleam@result:flatten(_pipe@2), _pipe@4 = gleam@result:map_error( _pipe@3, fun(_) -> {parse_error, none} end ), _pipe@5 = gleam@result:map( _pipe@4, fun(D) -> case gleam@list:is_empty(D) of true -> {error, {parse_error, none}}; false -> {ok, D} end end ), gleam@result:flatten(_pipe@5) end, gleam@result:'try'( Query, fun(Pairs) -> Query@1 = begin _pipe@6 = Pairs, maps:from_list(_pipe@6) end, parse_authorization_response_query(Query@1) end ). -file("src/flwr_oauth2/authorization_grant.gleam", 349). ?DOC( " Utility function to create a TokenRequest from an AuthorizationResponse.\n" " If the AuthorizationResponse is an ErrorResponse or an ImplicitGrantResponse returns Error(Nil), otherwise returns an AuthorizationCodeGrantTokenRequest.\n" ). -spec to_token_request( authorization_response(), gleam@uri:uri(), flwr_oauth2:client_authentication(), gleam@option:option(gleam@uri:uri()) ) -> {ok, flwr_oauth2:token_request()} | {error, nil}. to_token_request( Authorization_response, Token_endpoint, Authentication, Redirect_uri ) -> case Authorization_response of {code_grant_response, _, Code} -> _pipe = {authorization_code_grant_token_request, Token_endpoint, Authentication, Redirect_uri, Code}, {ok, _pipe}; _ -> {error, nil} end. -file("src/flwr_oauth2/authorization_grant.gleam", 371). ?DOC( " Utility function to create a TokenRequest from an AuthorizationResponse.\n" " If the AuthorizationResponse is an ErrorResponse or an ImplicitGrantResponse returns Error(Nil), otherwise returns an AuthorizationCodeGrantTokenRequest.\n" ). -spec to_token_request_with_pkce_verifier( authorization_response(), gleam@uri:uri(), flwr_oauth2:client_authentication(), gleam@option:option(gleam@uri:uri()), flwr_oauth2@pkce:verifier() ) -> {ok, flwr_oauth2:token_request()} | {error, nil}. to_token_request_with_pkce_verifier( Authorization_response, Token_endpoint, Authentication, Redirect_uri, Verifier ) -> case Authorization_response of {code_grant_response, _, Code} -> _pipe = {authorization_code_grant_token_request_with_p_k_c_e, Token_endpoint, Authentication, Redirect_uri, Code, erlang:element(2, Verifier)}, {ok, _pipe}; _ -> {error, nil} end. -file("src/flwr_oauth2/authorization_grant.gleam", 407). -spec response_type_to_string(response_type()) -> binary(). response_type_to_string(Response_type) -> case Response_type of code -> <<"code"/utf8>>; token -> <<"token"/utf8>> end. -file("src/flwr_oauth2/authorization_grant.gleam", 169). ?DOC(" Creates the uri that the resource owner should be redirected too.\n"). -spec make_redirect_uri(authorization_code_grant_request()) -> gleam@uri:uri(). make_redirect_uri(Redirect_config) -> State = begin _pipe = erlang:element(7, Redirect_config), _pipe@1 = gleam@option:map(_pipe, fun(X) -> erlang:element(2, X) end), gleam@option:map( _pipe@1, fun(_capture) -> flwr_oauth2@helpers:wrap_tuple(<<"state"/utf8>>, _capture) end ) end, Redirect_uri = flwr_oauth2@helpers:encode_redirect_uri( erlang:element(4, Redirect_config) ), Code_challenge = begin _pipe@2 = erlang:element(8, Redirect_config), gleam@option:map( _pipe@2, fun(_capture@1) -> flwr_oauth2@helpers:wrap_tuple( <<"code_challenge"/utf8>>, _capture@1 ) end ) end, Code_challenge_method = begin _pipe@3 = erlang:element(9, Redirect_config), gleam@option:map( _pipe@3, fun(X@1) -> {<<"code_challenge_method"/utf8>>, case X@1 of plain -> <<"plain"/utf8>>; s256 -> <<"S256"/utf8>> end} end ) end, Queries = begin _pipe@4 = [{<<"response_type"/utf8>>, response_type_to_string(erlang:element(3, Redirect_config))}, {<<"client_id"/utf8>>, erlang:element(2, erlang:element(5, Redirect_config))}, {<<"scope"/utf8>>, gleam@string:join( erlang:element(6, Redirect_config), <<" "/utf8>> )}], _pipe@5 = flwr_oauth2@helpers:add_if_present(_pipe@4, Redirect_uri), _pipe@6 = flwr_oauth2@helpers:add_if_present(_pipe@5, State), _pipe@7 = flwr_oauth2@helpers:add_if_present( _pipe@6, Code_challenge_method ), flwr_oauth2@helpers:add_if_present(_pipe@7, Code_challenge) end, _record = erlang:element(2, Redirect_config), {uri, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), erlang:element(6, _record), {some, gleam@uri:query_to_string(Queries)}, erlang:element(8, _record)}. -file("src/flwr_oauth2/authorization_grant.gleam", 397). ?DOC( " Generates a random State with the specified length including only uppercase and lowercase letters\n" " If length <= 0 returns an empty string\n" ). -spec random_state(integer()) -> state(). random_state(Length) -> _pipe = flwr_oauth2@helpers:generate_random_string( <<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"/utf8>>, Length ), {state, _pipe}. -file("src/flwr_oauth2/authorization_grant.gleam", 403). ?DOC(" Generates a random 32 character long State\n"). -spec random_state32() -> state(). random_state32() -> random_state(32).