Packages
oidcc
3.5.1
3.7.2
3.7.1
3.7.0
3.6.0
3.5.2
3.5.1
3.5.0
retired
3.4.0
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.2.0-beta.3
3.2.0-beta.2
retired
3.2.0-beta.1
retired
3.1.2
3.1.2-beta.1
retired
3.1.1
retired
3.1.0
retired
3.1.0-beta.2
retired
3.1.0-beta.1
retired
3.0.2
3.0.1
retired
3.0.0
retired
3.0.0-rc.6
retired
3.0.0-rc.5
retired
3.0.0-rc.4
retired
3.0.0-rc.3
retired
3.0.0-rc.2
retired
3.0.0-rc.1
retired
3.0.0-alpha.5
retired
3.0.0-alpha.4
retired
3.0.0-alpha.3
retired
3.0.0-alpha.2
retired
3.0.0-alpha.1
retired
2.0.0-alpha.2
retired
2.0.0-alpha.1
retired
1.8.1
retired
1.8.0
retired
1.7.0
retired
1.6.0
retired
1.5.1
retired
1.5.0
retired
1.4.0
retired
1.3.0
retired
1.2.1
retired
1.2.0
retired
1.1.0
retired
1.0.1
retired
1.0.0
retired
OpenID Connect client library for the BEAM.
Current section
Files
Jump to
Current section
Files
src/oidcc_client_context.erl
-module(oidcc_client_context).
-feature(maybe_expr, enable).
-include("internal/doc.hrl").
?MODULEDOC("""
Client Configuration for authorization, token exchange, and userinfo.
For most projects, it makes sense to use `m:oidcc_provider_configuration_worker` and the high-level
interface of `oidcc`. In that case, direct usage of this module is not needed.
To use the record, import the definition:
```erlang
-include_lib(["oidcc/include/oidcc_client_context.hrl"]).
```
""").
?MODULEDOC(#{since => <<"3.0.0">>}).
-include("oidcc_client_context.hrl").
-include("oidcc_provider_configuration.hrl").
-include_lib("jose/include/jose_jwk.hrl").
-export_type([authenticated_opts/0]).
-export_type([authenticated_t/0]).
-export_type([error/0]).
-export_type([opts/0]).
-export_type([t/0]).
-export_type([unauthenticated_opts/0]).
-export_type([unauthenticated_t/0]).
-export([from_configuration_worker/3]).
-export([from_configuration_worker/4]).
-export([from_manual/4]).
-export([from_manual/5]).
-export([apply_profiles/2]).
-type t() :: authenticated_t() | unauthenticated_t().
?DOC(#{since => <<"3.0.0">>}).
-type authenticated_t() :: #oidcc_client_context{
provider_configuration :: oidcc_provider_configuration:t(),
jwks :: jose_jwk:key(),
client_id :: binary(),
client_secret :: binary(),
client_jwks :: jose_jwk:key() | none
}.
?DOC(#{since => <<"3.0.0">>}).
-type unauthenticated_t() :: #oidcc_client_context{
provider_configuration :: oidcc_provider_configuration:t(),
jwks :: jose_jwk:key(),
client_id :: binary(),
client_secret :: unauthenticated,
client_jwks :: none
}.
?DOC(#{since => <<"3.0.0">>}).
-type authenticated_opts() :: #{
client_jwks => jose_jwk:key()
}.
?DOC(#{since => <<"3.0.0">>}).
-type unauthenticated_opts() :: #{}.
?DOC(#{since => <<"3.0.0">>}).
-type opts() :: authenticated_opts() | unauthenticated_opts().
?DOC(#{since => <<"3.0.0">>}).
-type error() :: provider_not_ready.
?DOC("""
Create Client Context from a `m:oidcc_provider_configuration_worker`.
See `from_configuration_worker/4`.
""").
?DOC(#{since => <<"3.0.0">>}).
-spec from_configuration_worker
(ProviderName, ClientId, ClientSecret) -> {ok, authenticated_t()} | {error, error()} when
ProviderName :: gen_server:server_ref(),
ClientId :: binary(),
ClientSecret :: binary();
(ProviderName, ClientId, ClientSecret) -> {ok, unauthenticated_t()} | {error, error()} when
ProviderName :: gen_server:server_ref(),
ClientId :: binary(),
ClientSecret :: unauthenticated.
from_configuration_worker(ProviderName, ClientId, ClientSecret) ->
from_configuration_worker(ProviderName, ClientId, ClientSecret, #{}).
?DOC("""
Create Client Context from a `m:oidcc_provider_configuration_worker`.
## Examples
```erlang
{ok, Pid} =
oidcc_provider_configuration_worker:start_link(#{
issuer => <<"https://login.salesforce.com">>
}),
{ok, #oidcc_client_context{}} =
oidcc_client_context:from_configuration_worker(Pid,
<<"client_id">>,
<<"client_secret">>).
```
```erlang
{ok, Pid} =
oidcc_provider_configuration_worker:start_link(#{
issuer => <<"https://login.salesforce.com">>,
name => {local, salesforce_provider}
}),
{ok, #oidcc_client_context{}} =
oidcc_client_context:from_configuration_worker(
salesforce_provider,
<<"client_id">>,
<<"client_secret">>,
#{client_jwks => jose_jwk:generate_key(16)}
).
```
""").
?DOC(#{since => <<"3.0.0">>}).
-spec from_configuration_worker
(ProviderName, ClientId, ClientSecret, Opts) ->
{ok, authenticated_t()} | {error, error()}
when
ProviderName :: gen_server:server_ref(),
ClientId :: binary(),
ClientSecret :: binary(),
Opts :: authenticated_opts();
(ProviderName, ClientId, ClientSecret, Opts) ->
{ok, unauthenticated_t()} | {error, error()}
when
ProviderName :: gen_server:server_ref(),
ClientId :: binary(),
ClientSecret :: unauthenticated,
Opts :: unauthenticated_opts().
from_configuration_worker(ProviderName, ClientId, ClientSecret, Opts) when is_pid(ProviderName) ->
maybe
#oidcc_provider_configuration{} =
ProviderConfiguration ?=
oidcc_provider_configuration_worker:get_provider_configuration(ProviderName),
#jose_jwk{} = Jwks ?= oidcc_provider_configuration_worker:get_jwks(ProviderName),
{ok,
from_manual(
ProviderConfiguration,
Jwks,
ClientId,
ClientSecret,
Opts
)}
else
undefined -> {error, provider_not_ready}
end;
from_configuration_worker(ProviderName, ClientId, ClientSecret, Opts) ->
case erlang:whereis(ProviderName) of
undefined ->
{error, provider_not_ready};
Pid ->
from_configuration_worker(Pid, ClientId, ClientSecret, Opts)
end.
?DOC("""
Create Client Context manually.
See `from_manual/5`.
""").
?DOC(#{since => <<"3.0.0">>}).
-spec from_manual
(Configuration, Jwks, ClientId, ClientSecret) -> authenticated_t() when
Configuration :: oidcc_provider_configuration:t(),
Jwks :: jose_jwk:key(),
ClientId :: binary(),
ClientSecret :: binary();
(Configuration, Jwks, ClientId, ClientSecret) -> unauthenticated_t() when
Configuration :: oidcc_provider_configuration:t(),
Jwks :: jose_jwk:key(),
ClientId :: binary(),
ClientSecret :: unauthenticated.
from_manual(Configuration, Jwks, ClientId, ClientSecret) ->
from_manual(Configuration, Jwks, ClientId, ClientSecret, #{}).
?DOC("""
Create Client Context manually.
## Examples
```erlang
{ok, Configuration} =
oidcc_provider_configuration:load_configuration(<<"https://login.salesforce.com">>, []),
#oidcc_provider_configuration{jwks_uri = JwksUri} = Configuration,
{ok, Jwks} = oidcc_provider_configuration:load_jwks(JwksUri, []).
#oidcc_client_context{} =
oidcc_client_context:from_manual(
Metadata,
Jwks,
<<"client_id">>,
<<"client_secret">>,
#{client_jwks => jose_jwk:generate_key(16)}
).
```
""").
?DOC(#{since => <<"3.0.0">>}).
-spec from_manual
(Configuration, Jwks, ClientId, ClientSecret, Opts) -> authenticated_t() when
Configuration :: oidcc_provider_configuration:t(),
Jwks :: jose_jwk:key(),
ClientId :: binary(),
ClientSecret :: binary(),
Opts :: authenticated_opts();
(Configuration, Jwks, ClientId, ClientSecret, Opts) -> unauthenticated_t() when
Configuration :: oidcc_provider_configuration:t(),
Jwks :: jose_jwk:key(),
ClientId :: binary(),
ClientSecret :: unauthenticated,
Opts :: unauthenticated_opts().
from_manual(
#oidcc_provider_configuration{} = Configuration,
#jose_jwk{} = Jwks,
ClientId,
unauthenticated,
_Opts
) when is_binary(ClientId) ->
#oidcc_client_context{
provider_configuration = Configuration,
jwks = Jwks,
client_id = ClientId,
client_secret = unauthenticated
};
from_manual(
#oidcc_provider_configuration{} = Configuration,
#jose_jwk{} = Jwks,
ClientId,
ClientSecret,
Opts
) when is_binary(ClientId), is_binary(ClientSecret) ->
#oidcc_client_context{
provider_configuration = Configuration,
jwks = Jwks,
client_id = ClientId,
client_secret = ClientSecret,
client_jwks = maps:get(client_jwks, Opts, none)
}.
?DOC("""
Apply OpenID Connect / OAuth2 Profiles to the context.
Currently, the only supported profiles are:
- `fapi2_security_profile` - https://openid.bitbucket.io/fapi/fapi-2_0-security-profile.html
- `fapi2_message_signing` - https://openid.bitbucket.io/fapi/fapi-2_0-message-signing.html
It returns an updated `t:t/0` record and a map of options to
be merged into the `m:oidcc_authorization` and `m:oidcc_token` functions.
## Examples
```erlang
ClientContext = #oidcc_client_context{} = oidcc_client_context:from_...(...),
{#oidcc_client_context{} = ClientContext1, Opts} = oidcc_client_context:apply_profiles(
ClientContext,
#{
profiles => [fapi2_message_signing]
}),
{ok, Uri} = oidcc_authorization:create_redirect_uri(
ClientContext1,
maps:merge(Opts, #{...})
).
```
""").
?DOC(#{since => <<"3.2.0">>}).
-spec apply_profiles(ClientContext, oidcc_profile:opts()) ->
{ok, ClientContext, oidcc_profile:opts_no_profiles()} | {error, oidcc_profile:error()}
when
ClientContext :: oidcc_client_context:t().
apply_profiles(ClientContext, Opts) ->
oidcc_profile:apply_profiles(ClientContext, Opts).