View Source oidcc_token (Oidcc v3.2.0-beta.3)
Facilitate OpenID Code/Token Exchanges
Records
To use the records, import the definition:
-include_lib(["oidcc/include/oidcc_token.hrl"]).
Telemetry
See'Elixir.Oidcc.Token'
Summary
Types
Access Token Wrapper
Refresh Token Wrapper
Options for retrieving a token
Token Response Wrapper
Options for refreshing a token
Functions
Authorization headers
Retrieve Client Credential Token
Retrieve JSON Web Token (JWT) Profile Token
Refresh Token
retrieve the token using the authcode received before and directly validate the result.
Validate ID Token
Validate the JARM response, returning the valid claims as a map.
Validate JWT
Types
access/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type access() :: #oidcc_token_access{token :: binary(), expires :: pos_integer() | undefined, type :: binary()}.
Access Token Wrapper
Fields
token
- The retrieved tokenexpires
- Number of seconds the token is valid
authorization_headers_opts/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type authorization_headers_opts() :: #{dpop_nonce => binary()}.
client_credentials_opts/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type client_credentials_opts() :: #{scope => oidcc_scope:scopes(), refresh_jwks => oidcc_jwt_util:refresh_jwks_for_unknown_kid_fun(), request_opts => oidcc_http_util:request_opts(), url_extension => oidcc_http_util:query_params(), body_extension => oidcc_http_util:query_params()}.
error/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type error() :: {missing_claim, MissingClaim :: binary(), Claims :: oidcc_jwt_util:claims()} | pkce_verifier_required | no_supported_auth_method | bad_access_token_hash | sub_invalid | token_expired | token_not_yet_valid | {none_alg_used, Token :: t()} | {missing_claim, ExpClaim :: {binary(), term()}, Claims :: oidcc_jwt_util:claims()} | {grant_type_not_supported, authorization_code | refresh_token | jwt_bearer | client_credentials} | {invalid_property, {Field :: id_token | refresh_token | access_token | expires_in | scopes, GivenValue :: term()}} | oidcc_jwt_util:error() | oidcc_http_util:error().
id/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type id() :: #oidcc_token_id{token :: binary(), claims :: oidcc_jwt_util:claims()}.
jwt_profile_opts/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type jwt_profile_opts() :: #{scope => oidcc_scope:scopes(), refresh_jwks => oidcc_jwt_util:refresh_jwks_for_unknown_kid_fun(), request_opts => oidcc_http_util:request_opts(), kid => binary(), url_extension => oidcc_http_util:query_params(), body_extension => oidcc_http_util:query_params()}.
refresh/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type refresh() :: #oidcc_token_refresh{token :: binary()}.
Refresh Token Wrapper
Fields
token
- The retrieved token
refresh_opts/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type refresh_opts() :: #{scope => oidcc_scope:scopes(), refresh_jwks => oidcc_jwt_util:refresh_jwks_for_unknown_kid_fun(), expected_subject := binary(), request_opts => oidcc_http_util:request_opts(), url_extension => oidcc_http_util:query_params(), body_extension => oidcc_http_util:query_params()}.
refresh_opts_no_sub/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type refresh_opts_no_sub() :: #{scope => oidcc_scope:scopes(), refresh_jwks => oidcc_jwt_util:refresh_jwks_for_unknown_kid_fun(), request_opts => oidcc_http_util:request_opts(), url_extension => oidcc_http_util:query_params(), body_extension => oidcc_http_util:query_params()}.
refresh_opts_no_sub()
retrieve_opts/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type retrieve_opts() :: #{pkce_verifier => binary(), require_pkce => boolean(), nonce => binary() | any, scope => oidcc_scope:scopes(), preferred_auth_methods => [oidcc_auth_util:auth_method(), ...], refresh_jwks => oidcc_jwt_util:refresh_jwks_for_unknown_kid_fun(), redirect_uri => uri_string:uri_string(), request_opts => oidcc_http_util:request_opts(), url_extension => oidcc_http_util:query_params(), body_extension => oidcc_http_util:query_params(), dpop_nonce => binary(), trusted_audiences => [binary()] | any}.
Options for retrieving a token
See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3
Fields
pkce_verifier
- pkce verifier (random string previously given tooidcc_authorization
), seehttps://datatracker.ietf.org/doc/html/rfc7636#section-4.1
require_pkce
- whether to require PKCE when getting the tokennonce
- Nonce to checkscope
- Scope to store with the tokenrefresh_jwks
- How to handle tokens with an unknownkid
. Seeoidcc_jwt_util:refresh_jwks_for_unknown_kid_fun()
redirect_uri
- Redirect uri given tooidcc_authorization:create_redirect_url/2
dpop_nonce
- if using DPoP, thenonce
value to use in the proof claimtrusted_audiences
- if present, a list of additional audience values to accept. Defaults toany
which allows any additional values
t/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type t() :: #oidcc_token{id :: oidcc_token:id() | none, access :: oidcc_token:access() | none, refresh :: oidcc_token:refresh() | none, scope :: oidcc_scope:scopes()}.
Token Response Wrapper
Fields
id
-id()
access
-access()
refresh
-refresh()
scope
-oidcc_scope:scopes()
validate_jarm_opts/0
View Source (since 3.0.0 -------------------------------------------------------------------)-type validate_jarm_opts() :: #{trusted_audiences => [binary()] | any}.
Options for refreshing a token
See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3
Fields
scope
- Scope to store with the tokenrefresh_jwks
- How to handle tokens with an unknownkid
. Seeoidcc_jwt_util:refresh_jwks_for_unknown_kid_fun()
expected_subject
-sub
of the original token
validate_jwt_opts/0
View Source (since 3.0.0 -------------------------------------------------------------------)Functions
authorization_headers(AccessTokenRecord, Method, Endpoint, ClientContext)
View Source (since 3.2.0)-spec authorization_headers(AccessTokenRecord, Method, Endpoint, ClientContext) -> HeaderMap when AccessTokenRecord :: access(), Method :: post | get, Endpoint :: uri_string:uri_string(), ClientContext :: oidcc_client_context:t(), HeaderMap :: #{binary() => binary()}.
Authorization headers
Generate a map of authorization headers to use when using the given access token to access an API endpoint.
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
%% Get Access Token record from somewhere
Headers =
oidcc:authorization_headers(AccessTokenRecord, :get, Url, ClientContext).
authorization_headers(AccessTokenRecord, Method, Endpoint, ClientContext, Opts)
View Source (since 3.0.0 -------------------------------------------------------------------)-spec authorization_headers(AccessTokenRecord, Method, Endpoint, ClientContext, Opts) -> HeaderMap when AccessTokenRecord :: access(), Method :: post | get, Endpoint :: uri_string:uri_string(), ClientContext :: oidcc_client_context:t(), Opts :: authorization_headers_opts(), HeaderMap :: #{binary() => binary()}.
-spec client_credentials(ClientContext, Opts) -> {ok, t()} | {error, error()} when ClientContext :: oidcc_client_context:authenticated_t(), Opts :: client_credentials_opts().
Retrieve Client Credential Token
See https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.4
For a high level interface using oidcc_provider_configuration_worker
see oidcc:client_credentials_token/4
.
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
{ok, #oidcc_token{}} =
oidcc_token:client_credentials(ClientContext,
#{scope => [<<"scope">>]}).
-spec jwt_profile(Subject, ClientContext, Jwk, Opts) -> {ok, t()} | {error, error()} when Subject :: binary(), ClientContext :: oidcc_client_context:t(), Jwk :: jose_jwk:key(), Opts :: jwt_profile_opts().
Retrieve JSON Web Token (JWT) Profile Token
See https://datatracker.ietf.org/doc/html/rfc7523#section-4
For a high level interface using oidcc_provider_configuration_worker
see oidcc:jwt_profile_token/6
.
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
{ok, KeyJson} = file:read_file("jwt-profile.json"),
KeyMap = jose:decode(KeyJson),
Key = jose_jwk:from_pem(maps:get(<<"key">>, KeyMap)),
{ok, #oidcc_token{}} =
oidcc_token:jwt_profile(<<"subject">>,
ClientContext,
Key,
#{scope => [<<"scope">>],
kid => maps:get(<<"keyId">>, KeyMap)}).
-spec refresh(RefreshToken, ClientContext, Opts) -> {ok, t()} | {error, error()} when RefreshToken :: binary(), ClientContext :: oidcc_client_context:t(), Opts :: refresh_opts(); (Token, ClientContext, Opts) -> {ok, t()} | {error, error()} when Token :: oidcc_token:t(), ClientContext :: oidcc_client_context:t(), Opts :: refresh_opts_no_sub().
Refresh Token
For a high level interface using oidcc_provider_configuration_worker
see oidcc:refresh_token/5
.
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
%% Get AuthCode from Redirect
{ok, Token} =
oidcc_token:retrieve(AuthCode, ClientContext, #{
redirect_uri => <<"https://example.com/callback">>}).
%% Later
{ok, #oidcc_token{}} =
oidcc_token:refresh(Token,
ClientContext,
#{expected_subject => <<"sub_from_initial_id_token>>}).
-spec retrieve(AuthCode, ClientContext, Opts) -> {ok, t()} | {error, error()} when AuthCode :: binary(), ClientContext :: oidcc_client_context:t(), Opts :: retrieve_opts().
retrieve the token using the authcode received before and directly validate the result.
the authcode was sent to the local endpoint by the OpenId Connect provider, using redirects
For a high level interface using oidcc_provider_configuration_worker
see oidcc:retrieve_token/5
.
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
%% Get AuthCode from Redirect
{ok, #oidcc_token{}} =
oidcc:retrieve(AuthCode, ClientContext, #{
redirect_uri => <<"https://example.com/callback">>}).
validate_id_token(IdToken, ClientContext, NonceOrOpts)
View Source (since 3.0.0)-spec validate_id_token(IdToken, ClientContext, NonceOrOpts) -> {ok, Claims} | {error, error()} when IdToken :: binary(), ClientContext :: oidcc_client_context:t(), NonceOrOpts :: Nonce | retrieve_opts(), Nonce :: binary() | any, Claims :: oidcc_jwt_util:claims().
Validate ID Token
Usually the id token is validated using retrieve/3
. If you get the token passed from somewhere else, this function can validate it.
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
%% Get IdToken from somewhere
{ok, Claims} =
oidcc:validate_id_token(IdToken, ClientContext, ExpectedNonce).
-spec validate_jarm(Response, ClientContext, Opts) -> {ok, oidcc_jwt_util:claims()} | {error, error()} when Response :: binary(), ClientContext :: oidcc_client_context:t(), Opts :: validate_jarm_opts().
Validate the JARM response, returning the valid claims as a map.
The response was sent to the local endpoint by the OpenId Connect provider, using redirects
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
%% Get Response from Redirect
{ok, #{<<"code">> := AuthCode}} =
oidcc:validate_jarm(Response, ClientContext, #{}),
{ok, #oidcc_token{}} = oidcc:retrieve(AuthCode, ClientContext,
#{redirect_uri => <<"https://redirect.example/">>}.
-spec validate_jwt(Jwt, ClientContext, Opts) -> {ok, Claims} | {error, error()} when Jwt :: binary(), ClientContext :: oidcc_client_context:t(), Opts :: validate_jwt_opts(), Claims :: oidcc_jwt_util:claims().
Validate JWT
Validates a generic JWT (such as an access token) from the given provider. Useful if the issuer is shared between multiple applications, and the access token generated for a user at one client is used to validate their access at another client.
Examples
{ok, ClientContext} =
oidcc_client_context:from_configuration_worker(provider_name,
<<"client_id">>,
<<"client_secret">>),
%% Get Jwt from Authorization header
{ok, Claims} =
oidcc:validate_jwt(Jwt, ClientContext, Opts).