diff --git a/src/nova_auth_oidc.erl b/src/nova_auth_oidc.erl deleted file mode 100644 index 4cf1ed2..0000000 --- a/src/nova_auth_oidc.erl +++ /dev/null @@ -1,53 +0,0 @@ --module(nova_auth_oidc). --moduledoc ~""" -Behaviour for OIDC provider configuration. Implementing modules define -provider endpoints, client credentials, scopes, and claims mapping. - -Example: -``` --module(my_oidc_config). --behaviour(nova_auth_oidc). --export([config/0]). - -config() -> - #{ - providers => #{ - google => #{ - client_id => os:getenv("GOOGLE_CLIENT_ID"), - client_secret => os:getenv("GOOGLE_CLIENT_SECRET"), - discovery_url => ~"https://accounts.google.com/.well-known/openid-configuration" - } - }, - scopes => [~"openid", ~"profile", ~"email"], - claims_mapping => #{ - ~"sub" => provider_uid, - ~"email" => provider_email, - ~"name" => provider_display_name - } - }. -``` -""". - --export_type([oidc_config/0, provider_config/0]). - --type provider_config() :: #{ - client_id := binary() | string(), - client_secret := binary() | string(), - discovery_url => binary(), - authorize_url => binary(), - token_url => binary(), - userinfo_url => binary(), - jwks_uri => binary() -}. - --type oidc_config() :: #{ - providers := #{atom() => provider_config()}, - base_url => binary(), - auth_path_prefix => binary(), - scopes => [binary()], - claims_mapping => #{binary() => atom()} | {module(), atom()}, - on_success => {redirect, binary()} | {status, pos_integer()}, - on_failure => {redirect, binary()} | {status, pos_integer()} -}. - --callback config() -> oidc_config(). diff --git a/src/nova_auth_oidc_jwt.erl b/src/nova_auth_oidc_jwt.erl deleted file mode 100644 index 308a56b..0000000 --- a/src/nova_auth_oidc_jwt.erl +++ /dev/null @@ -1,63 +0,0 @@ --module(nova_auth_oidc_jwt). --moduledoc ~""" -Validates OIDC ID tokens (JWTs) against provider configuration. - -Extracts and validates the payload from a JWT, maps claims using -the configured claims mapping, and returns an actor map. -""". - --export([validate_token/3]). - --doc ~""" -Validate an OIDC ID token for the given provider. - -Decodes the JWT payload, verifies basic structure, and maps claims -according to the OIDC configuration module's `claims_mapping`. - -Returns `{ok, Actor}` with mapped claims or `{error, Reason}`. -""". --spec validate_token(module(), atom(), binary()) -> - {ok, nova_auth:actor()} | {error, term()}. -validate_token(ConfigMod, Provider, Token) -> - Config = ConfigMod:config(), - Providers = maps:get(providers, Config, #{}), - case maps:find(Provider, Providers) of - {ok, _ProviderConfig} -> - case decode_jwt_payload(Token) of - {ok, Claims} -> - Mapping = maps:get(claims_mapping, Config, #{}), - Actor = nova_auth_claims:map(Mapping, Claims, #{provider => Provider}), - {ok, #{ - id => maps:get(provider_uid, Actor, maps:get(~"sub", Claims, undefined)), - claims => Actor - }}; - {error, Reason} -> - {error, Reason} - end; - error -> - {error, unknown_provider} - end. - -%% Decode the payload section of a JWT (base64url-encoded JSON). --spec decode_jwt_payload(binary()) -> {ok, map()} | {error, term()}. -decode_jwt_payload(Token) -> - case binary:split(Token, ~".", [global]) of - [_, PayloadB64, _] -> - decode_payload_b64(PayloadB64); - _ -> - {error, invalid_jwt_format} - end. - --spec decode_payload_b64(binary()) -> {ok, map()} | {error, invalid_jwt}. -decode_payload_b64(PayloadB64) -> - try base64:decode(PayloadB64, #{mode => urlsafe, padding => false}) of - Decoded -> - try json:decode(Decoded) of - Map when is_map(Map) -> {ok, Map}; - _ -> {error, invalid_jwt} - catch - _:_ -> {error, invalid_jwt} - end - catch - _:_ -> {error, invalid_jwt} - end.