Skip to content

Commit

Permalink
fix: allow overriding strategy defaults
Browse files Browse the repository at this point in the history
`auto_set_fields` doesn't set defaults, it sets the values *always*
and so things like `authorization_params` were not settable

fixes #764
  • Loading branch information
zachdaniel committed Aug 11, 2024
1 parent ccd0eb0 commit e93a9ac
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 30 deletions.
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.15.6
erlang 26.1
elixir 1.17.2-otp-27
erlang 27.0
5 changes: 5 additions & 0 deletions documentation/dsls/DSL:-AshAuthentication.Strategy.Auth0.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,13 @@ The following defaults are applied:
| [`redirect_uri`](#authentication-strategies-auth0-redirect_uri){: #authentication-strategies-auth0-redirect_uri .spark-required} | `(any, any -> any) \| module \| String.t` | | The callback URI *base*. Not the whole URI back to the callback endpoint, but the URI to your `AuthPlug`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`base_url`](#authentication-strategies-auth0-base_url){: #authentication-strategies-auth0-base_url } | `(any, any -> any) \| module \| String.t` | | The base URL of the OAuth2 server - including the leading protocol (ie `https://`). Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`site`](#authentication-strategies-auth0-site){: #authentication-strategies-auth0-site } | `(any, any -> any) \| module \| String.t` | | Deprecated: Use `base_url` instead. |
| [`auth_method`](#authentication-strategies-auth0-auth_method){: #authentication-strategies-auth0-auth_method } | `nil \| :client_secret_basic \| :client_secret_post \| :client_secret_jwt \| :private_key_jwt` | `:client_secret_post` | The authentication strategy used, optional. If not set, no authentication will be used during the access token request. |
| [`client_secret`](#authentication-strategies-auth0-client_secret){: #authentication-strategies-auth0-client_secret } | `(any, any -> any) \| module \| String.t` | | The OAuth2 client secret. Required if :auth_method is `:client_secret_basic`, `:client_secret_post` or `:client_secret_jwt`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`authorize_url`](#authentication-strategies-auth0-authorize_url){: #authentication-strategies-auth0-authorize_url } | `(any, any -> any) \| module \| String.t` | `"/authorize"` | The API url to the OAuth2 authorize endpoint, relative to `site`, e.g `authorize_url fn _, _ -> {:ok, "https://exampe.com/authorize"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`token_url`](#authentication-strategies-auth0-token_url){: #authentication-strategies-auth0-token_url } | `(any, any -> any) \| module \| String.t` | `"/oauth/token"` | The API url to access the token endpoint, relative to `site`, e.g `token_url fn _, _ -> {:ok, "https://example.com/oauth_token"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`user_url`](#authentication-strategies-auth0-user_url){: #authentication-strategies-auth0-user_url } | `(any, any -> any) \| module \| String.t` | `"/userinfo"` | The API url to access the user endpoint, relative to `site`, e.g `user_url fn _, _ -> {:ok, "https://example.com/userinfo"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`private_key`](#authentication-strategies-auth0-private_key){: #authentication-strategies-auth0-private_key } | `(any, any -> any) \| module \| String.t` | | The private key to use if `:auth_method` is `:private_key_jwt`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`authorization_params`](#authentication-strategies-auth0-authorization_params){: #authentication-strategies-auth0-authorization_params } | `keyword` | `[scope: "openid profile email"]` | Any additional parameters to encode in the request phase. eg: `authorization_params scope: "openid profile email"` |
| [`registration_enabled?`](#authentication-strategies-auth0-registration_enabled?){: #authentication-strategies-auth0-registration_enabled? } | `boolean` | `true` | If enabled, new users will be able to register for your site when authenticating and not already present. If not, only existing users will be able to authenticate. |
| [`register_action_name`](#authentication-strategies-auth0-register_action_name){: #authentication-strategies-auth0-register_action_name } | `atom` | | The name of the action to use to register a user, if `registration_enabled?` is `true`. Defaults to `register_with_<name>` See the "Registration and Sign-in" section of the strategy docs for more. |
| [`sign_in_action_name`](#authentication-strategies-auth0-sign_in_action_name){: #authentication-strategies-auth0-sign_in_action_name } | `atom` | | The name of the action to use to sign in an existing user, if `sign_in_enabled?` is `true`. Defaults to `sign_in_with_<strategy>`, which is generated for you by default. See the "Registration and Sign-in" section of the strategy docs for more information. |
Expand Down
6 changes: 6 additions & 0 deletions documentation/dsls/DSL:-AshAuthentication.Strategy.Github.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,15 @@ The following defaults are applied:
|------|------|---------|------|
| [`client_id`](#authentication-strategies-github-client_id){: #authentication-strategies-github-client_id .spark-required} | `(any, any -> any) \| module \| String.t` | | The OAuth2 client ID. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`redirect_uri`](#authentication-strategies-github-redirect_uri){: #authentication-strategies-github-redirect_uri .spark-required} | `(any, any -> any) \| module \| String.t` | | The callback URI *base*. Not the whole URI back to the callback endpoint, but the URI to your `AuthPlug`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`base_url`](#authentication-strategies-github-base_url){: #authentication-strategies-github-base_url } | `(any, any -> any) \| module \| String.t` | `"https://api.github.com"` | The base URL of the OAuth2 server - including the leading protocol (ie `https://`). Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`site`](#authentication-strategies-github-site){: #authentication-strategies-github-site } | `(any, any -> any) \| module \| String.t` | | Deprecated: Use `base_url` instead. |
| [`auth_method`](#authentication-strategies-github-auth_method){: #authentication-strategies-github-auth_method } | `nil \| :client_secret_basic \| :client_secret_post \| :client_secret_jwt \| :private_key_jwt` | `:client_secret_post` | The authentication strategy used, optional. If not set, no authentication will be used during the access token request. |
| [`client_secret`](#authentication-strategies-github-client_secret){: #authentication-strategies-github-client_secret } | `(any, any -> any) \| module \| String.t` | | The OAuth2 client secret. Required if :auth_method is `:client_secret_basic`, `:client_secret_post` or `:client_secret_jwt`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`authorize_url`](#authentication-strategies-github-authorize_url){: #authentication-strategies-github-authorize_url } | `(any, any -> any) \| module \| String.t` | `"https://github.com/login/oauth/authorize"` | The API url to the OAuth2 authorize endpoint, relative to `site`, e.g `authorize_url fn _, _ -> {:ok, "https://exampe.com/authorize"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`token_url`](#authentication-strategies-github-token_url){: #authentication-strategies-github-token_url } | `(any, any -> any) \| module \| String.t` | `"https://github.com/login/oauth/access_token"` | The API url to access the token endpoint, relative to `site`, e.g `token_url fn _, _ -> {:ok, "https://example.com/oauth_token"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`user_url`](#authentication-strategies-github-user_url){: #authentication-strategies-github-user_url } | `(any, any -> any) \| module \| String.t` | `"/user"` | The API url to access the user endpoint, relative to `site`, e.g `user_url fn _, _ -> {:ok, "https://example.com/userinfo"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`private_key`](#authentication-strategies-github-private_key){: #authentication-strategies-github-private_key } | `(any, any -> any) \| module \| String.t` | | The private key to use if `:auth_method` is `:private_key_jwt`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`authorization_params`](#authentication-strategies-github-authorization_params){: #authentication-strategies-github-authorization_params } | `keyword` | `[scope: "read:user,user:email"]` | Any additional parameters to encode in the request phase. eg: `authorization_params scope: "openid profile email"` |
| [`registration_enabled?`](#authentication-strategies-github-registration_enabled?){: #authentication-strategies-github-registration_enabled? } | `boolean` | `true` | If enabled, new users will be able to register for your site when authenticating and not already present. If not, only existing users will be able to authenticate. |
| [`register_action_name`](#authentication-strategies-github-register_action_name){: #authentication-strategies-github-register_action_name } | `atom` | | The name of the action to use to register a user, if `registration_enabled?` is `true`. Defaults to `register_with_<name>` See the "Registration and Sign-in" section of the strategy docs for more. |
| [`sign_in_action_name`](#authentication-strategies-github-sign_in_action_name){: #authentication-strategies-github-sign_in_action_name } | `atom` | | The name of the action to use to sign in an existing user, if `sign_in_enabled?` is `true`. Defaults to `sign_in_with_<strategy>`, which is generated for you by default. See the "Registration and Sign-in" section of the strategy docs for more information. |
Expand Down
6 changes: 6 additions & 0 deletions documentation/dsls/DSL:-AshAuthentication.Strategy.Google.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,15 @@ The following defaults are applied:
|------|------|---------|------|
| [`client_id`](#authentication-strategies-google-client_id){: #authentication-strategies-google-client_id .spark-required} | `(any, any -> any) \| module \| String.t` | | The OAuth2 client ID. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`redirect_uri`](#authentication-strategies-google-redirect_uri){: #authentication-strategies-google-redirect_uri .spark-required} | `(any, any -> any) \| module \| String.t` | | The callback URI *base*. Not the whole URI back to the callback endpoint, but the URI to your `AuthPlug`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`base_url`](#authentication-strategies-google-base_url){: #authentication-strategies-google-base_url } | `(any, any -> any) \| module \| String.t` | `"https://www.googleapis.com"` | The base URL of the OAuth2 server - including the leading protocol (ie `https://`). Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`site`](#authentication-strategies-google-site){: #authentication-strategies-google-site } | `(any, any -> any) \| module \| String.t` | | Deprecated: Use `base_url` instead. |
| [`auth_method`](#authentication-strategies-google-auth_method){: #authentication-strategies-google-auth_method } | `nil \| :client_secret_basic \| :client_secret_post \| :client_secret_jwt \| :private_key_jwt` | `:client_secret_post` | The authentication strategy used, optional. If not set, no authentication will be used during the access token request. |
| [`client_secret`](#authentication-strategies-google-client_secret){: #authentication-strategies-google-client_secret } | `(any, any -> any) \| module \| String.t` | | The OAuth2 client secret. Required if :auth_method is `:client_secret_basic`, `:client_secret_post` or `:client_secret_jwt`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`authorize_url`](#authentication-strategies-google-authorize_url){: #authentication-strategies-google-authorize_url } | `(any, any -> any) \| module \| String.t` | `"https://accounts.google.com/o/oauth2/v2/auth"` | The API url to the OAuth2 authorize endpoint, relative to `site`, e.g `authorize_url fn _, _ -> {:ok, "https://exampe.com/authorize"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`token_url`](#authentication-strategies-google-token_url){: #authentication-strategies-google-token_url } | `(any, any -> any) \| module \| String.t` | `"/oauth2/v4/token"` | The API url to access the token endpoint, relative to `site`, e.g `token_url fn _, _ -> {:ok, "https://example.com/oauth_token"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`user_url`](#authentication-strategies-google-user_url){: #authentication-strategies-google-user_url } | `(any, any -> any) \| module \| String.t` | `"/oauth2/v3/userinfo"` | The API url to access the user endpoint, relative to `site`, e.g `user_url fn _, _ -> {:ok, "https://example.com/userinfo"} end`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`private_key`](#authentication-strategies-google-private_key){: #authentication-strategies-google-private_key } | `(any, any -> any) \| module \| String.t` | | The private key to use if `:auth_method` is `:private_key_jwt`. Takes either a module which implements the `AshAuthentication.Secret` behaviour, a 2 arity anonymous function or a string. |
| [`authorization_params`](#authentication-strategies-google-authorization_params){: #authentication-strategies-google-authorization_params } | `keyword` | `[scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile"]` | Any additional parameters to encode in the request phase. eg: `authorization_params scope: "openid profile email"` |
| [`registration_enabled?`](#authentication-strategies-google-registration_enabled?){: #authentication-strategies-google-registration_enabled? } | `boolean` | `true` | If enabled, new users will be able to register for your site when authenticating and not already present. If not, only existing users will be able to authenticate. |
| [`register_action_name`](#authentication-strategies-google-register_action_name){: #authentication-strategies-google-register_action_name } | `atom` | | The name of the action to use to register a user, if `registration_enabled?` is `true`. Defaults to `register_with_<name>` See the "Registration and Sign-in" section of the strategy docs for more. |
| [`sign_in_action_name`](#authentication-strategies-google-sign_in_action_name){: #authentication-strategies-google-sign_in_action_name } | `atom` | | The name of the action to use to sign in an existing user, if `sign_in_enabled?` is `true`. Defaults to `sign_in_with_<strategy>`, which is generated for you by default. See the "Registration and Sign-in" section of the strategy docs for more information. |
Expand Down
13 changes: 4 additions & 9 deletions lib/ash_authentication/strategies/auth0/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule AshAuthentication.Strategy.Auth0.Dsl do
@moduledoc false

alias AshAuthentication.Strategy.{Custom, OAuth2}
alias Assent.Strategy.Auth0

@doc false
@spec dsl :: Custom.entity()
Expand All @@ -22,17 +23,11 @@ defmodule AshAuthentication.Strategy.Auth0.Dsl do
#### Strategy defaults:
#{strategy_override_docs(Assent.Strategy.Auth0)}
#{strategy_override_docs(Auth0)}
""",
auto_set_fields: strategy_fields(Assent.Strategy.Auth0, icon: :auth0)
auto_set_fields: [assent_strategy: Auth0, icon: :auth0]
})
end

defp strategy_fields(strategy, params) do
[]
|> strategy.default_config()
|> Keyword.put(:assent_strategy, strategy)
|> Keyword.merge(params)
|> Custom.set_defaults(Auth0.default_config([]))
end

defp strategy_override_docs(strategy) do
Expand Down
37 changes: 37 additions & 0 deletions lib/ash_authentication/strategies/custom.ex
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,41 @@ defmodule AshAuthentication.Strategy.Custom do
dsl_patches: [%Dsl.Patch.AddEntity{section_path: path, entity: entity}]
end
end

@doc """
Sets default values for a DSL schema based on a set of defaults.
If a given default is in the schema, it can be overriden, so we just set the default
and mark it not required.
If not, then we add it to `auto_set_fields`, and the user cannot override it.
"""
def set_defaults(dsl, defaults) do
Enum.reduce(defaults, dsl, fn {key, value}, dsl ->
if dsl.schema[key] do
set_default(dsl, key, value)
else
Map.update!(dsl, :auto_set_fields, &Keyword.put(&1, key, value))
end
end)
end

defp set_default(dsl, key, value) do
Map.update!(dsl, :schema, fn schema ->
Keyword.update(
schema,
key,
[
type: :any,
default: value,
hide: true
],
fn config ->
config
|> Keyword.put(:default, value)
|> Keyword.delete(:required)
end
)
end)
end
end
13 changes: 4 additions & 9 deletions lib/ash_authentication/strategies/github/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule AshAuthentication.Strategy.Github.Dsl do
@moduledoc false

alias AshAuthentication.Strategy.{Custom, OAuth2}
alias Assent.Strategy.Github

@doc false
@spec dsl :: Custom.entity()
Expand All @@ -22,17 +23,11 @@ defmodule AshAuthentication.Strategy.Github.Dsl do
#### Strategy defaults:
#{strategy_override_docs(Assent.Strategy.Github)}
#{strategy_override_docs(Github)}
""",
auto_set_fields: strategy_fields(Assent.Strategy.Github, icon: :github)
auto_set_fields: [icon: :github, assent_strategy: Github]
})
end

defp strategy_fields(strategy, params) do
[]
|> strategy.default_config()
|> Keyword.put(:assent_strategy, strategy)
|> Keyword.merge(params)
|> Custom.set_defaults(Github.default_config([]))
end

defp strategy_override_docs(strategy) do
Expand Down
13 changes: 4 additions & 9 deletions lib/ash_authentication/strategies/google/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule AshAuthentication.Strategy.Google.Dsl do
@moduledoc false

alias AshAuthentication.Strategy.{Custom, OAuth2}
alias Assent.Strategy.Google

@doc false
@spec dsl :: Custom.entity()
Expand All @@ -23,17 +24,11 @@ defmodule AshAuthentication.Strategy.Google.Dsl do
#### Strategy defaults:
#{strategy_override_docs(Assent.Strategy.Google)}
#{strategy_override_docs(Google)}
""",
auto_set_fields: strategy_fields(Assent.Strategy.Google, icon: :google)
auto_set_fields: [icon: :google, assent_strategy: Google]
})
end

defp strategy_fields(strategy, params) do
[]
|> strategy.default_config()
|> Keyword.put(:assent_strategy, strategy)
|> Keyword.merge(params)
|> Custom.set_defaults(Google.default_config([]))
end

defp strategy_override_docs(strategy) do
Expand Down
Loading

0 comments on commit e93a9ac

Please sign in to comment.