-
-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error with multitenant Azure login #37
Comments
Thanks, sorry for the delay, been super busy with work. So continuing from the elixirforum this is due to how OpenID specs works. There are some options you can try out. Use OAuth2 base strategyInstead of depending on OpenID, you could use the OAuth 2.0 base strategy with like this (same as what the ueberauth strategy does): [
client_id: "REPLACE_WITH_CLIENT_ID",
client_secret: "REPLACE_WITH_CLIENT_SECRET",
auth_method: :client_secret_post,
site: "https://graph.microsoft.com",
authorize_url: "https://login.microsoftonline.com/#{tenant_id}/oauth2/v2.0/authorize",
token_url: "https://login.microsoftonline.com/#{tenant_id}/oauth2/v2.0/token",
authorization_params: [scope: "https://graph.microsoft.com/user.read openid email offline_access"],
user_url: "https://graph.microsoft.com/v1.0/me/"
] Not sure if this works out of the box, but it would be pretty easy to set it up as a custom strategy to parse the right user struct. Dynamically set the tenant idYou may be able to continue using OIDC if you can fetch the tenant id from the returned auth token. This would require you to add a plug or similar, and then dynamically update the config like this: pow-auth/pow_assent#117 (comment) |
I assume this has been resolved 🙂 |
I did not managed to get it working without tenant id. |
With the new The latter could look something like this (untested): defmodule MyAppWeb.AzureADStrategy do
@moduledoc false
use Assent.Strategy.OIDC.Base
alias Assent.{Config, Strategy.OIDC}
@impl true
def default_config(config) do
[
site: "https://login.microsoftonline.com/common/v2.0",
authorization_params: [scope: "email profile", response_mode: "form_post"],
client_auth_method: :client_secret_post,
]
end
@impl true
def normalize(_config, user), do: {:ok, user}
@impl true
def get_user(config, token) do
with {:ok, issuer} <- fetch_iss(token["id_token"], config),
{:ok, config} <- update_issuer_in_config(config, issuer),
{:ok, jwt} <- OIDC.validate_id_token(config, token["id_token"]) do
Helpers.normalize_userinfo(jwt.claims)
end
end
defp fetch_iss(encoded, config) do
with [_, encoded, _] <- String.split(encoded, "."),
{:ok, json} <- Base.url_decode64(encoded, padding: false),
{:ok, claims} <- Config.json_library(config).decode(json) do
Map.fetch(claims, "iss")
else
{:error, error} -> {:error, error}
_any -> {:error, "The ID Token is not a valid JWT"}
end
end
defp update_issuer_in_config(config, issuer) do
openid_configuration = Map.put(config[:openid_configuration], "issuer", issuer)
{:ok, Map.put(config, :openid_configuration, openid_configuration)}
end
end |
In case it might help anyone, this version based on what Dan kindly provided above worked for me: defmodule MyApp.Assent.AzureADCommonStrategy do
@moduledoc false
use Assent.Strategy.OIDC.Base
alias Assent.{Config, Strategy.OIDC}
@impl true
def default_config(config) do
[
authorization_params: [scope: "email profile", response_mode: "form_post"],
client_auth_method: :client_secret_post,
site: "https://login.microsoftonline.com/common/v2.0"
]
end
@impl true
def normalize(_config, user), do: {:ok, user}
@impl true
def fetch_user(config, token) do
with {:ok, issuer} <- fetch_iss(token["id_token"], config),
{:ok, config} <- update_issuer_in_config(config, issuer),
{:ok, jwt} <- OIDC.validate_id_token(config, token["id_token"]) do
Helpers.normalize_userinfo(jwt.claims)
end
end
defp fetch_iss(encoded, config) do
with [_, encoded, _] <- String.split(encoded, "."),
{:ok, json} <- Base.url_decode64(encoded, padding: false),
{:ok, claims} <- Config.json_library(config).decode(json) do
Map.fetch(claims, "iss")
else
{:error, error} -> {:error, error}
_any -> {:error, "The ID Token is not a valid JWT"}
end
end
defp update_issuer_in_config(config, issuer) do
openid_configuration = Map.put(config[:openid_configuration], "issuer", issuer)
{:ok, Keyword.put(config, :openid_configuration, openid_configuration)}
end
end |
[error] #PID<0.888.0> running TaskAppWeb.Endpoint (connection #PID<0.828.0>, stream id 27) terminated
Server: localhost:4006 (https)
Request: POST /auth/azure/callback
** (exit) an exception was raised:
** (RuntimeError) Invalid issuer "https://login.microsoftonline.com/270a4662-e407-4044-b299-1a62945d3893/v2.0" in ID Token
(pow_assent 0.4.6) lib/pow_assent/phoenix/controllers/authorization_controller.ex:209: PowAssent.Phoenix.AuthorizationController.handle_strategy_error/1
(pow_assent 0.4.6) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.action/2
(pow_assent 0.4.6) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.phoenix_controller_pipeline/2
(phoenix 1.4.16) lib/phoenix/router.ex:288: Phoenix.Router.call/2
(task_app 0.1.0) lib/task_app_web/endpoint.ex:1: TaskAppWeb.Endpoint.plug_builder_call/2
(task_app 0.1.0) lib/plug/debugger.ex:132: TaskAppWeb.Endpoint."call (overridable 3)"/2
(task_app 0.1.0) lib/task_app_web/endpoint.ex:1: TaskAppWeb.Endpoint.call/2
(phoenix 1.4.16) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4
The text was updated successfully, but these errors were encountered: