pow-auth / assent Goto Github PK
View Code? Open in Web Editor NEWMulti-provider framework in Elixir
Home Page: https://powauth.com
License: MIT License
Multi-provider framework in Elixir
Home Page: https://powauth.com
License: MIT License
During compilation, I get the warnings below repeatedly. It seems to be because oauther
needs to have :crypto
and :public_key
its :extra_applications
config.
I raised it here: lexmag/oauther#18
I also notice it's not seen a commit in over 2.5 years, so I thought I would bring the point up over here, as well.
Thank you, Dan, for all the hard work & sharing!
It would be good to see it support LINE OAuth Provider (https://developers.line.biz/en/services/line-login/). I can open PR if you're all agree.
The client_secret generated by Assent.JWTAdapter.AssentJWT doesn't have a valid signature and returns an "invalid_client" error when handling the callback from Apple. I confirmed that the signature was not valid by decoding the client secret at https://jwt.io/ and providing the public key for my Apple generated private key.
In case this helps, I used the following command to generate a public key from the private key:
openssl ec -in AuthKey_xxxxxxxxx.p8 -pubout -out public.pem
Switching to Assent.JWTAdapter.JOSE adapter does generate the correct client secret.
It is becoming an OAuth recommendation that state and code_verifier/code_challenge be used together to ensure that nobody can hijack your OAuth exchange code in server flows.
This simply allows you to pass your verifier to the oauth2 callback (it was literally impossible before) in case you need to. It is up to the user to generate your challenge and encode it.
This is an MVP for my use case so I am opening an issue and immediately opening a pull request for it.
When using the Assent.JWTAdapter.JOSE for Assent.Strategy.Apple, the following error occurs:
** (FunctionClauseError) no function clause matching in Assent.JWTAdapter.JOSE.jwk/2
The following arguments were given to Assent.JWTAdapter.JOSE.jwk/2:
# 1
"RS256"
# 2
nil
Attempted function clauses (showing 3 out of 3):
defp jwk(<<"HS"::binary(), _rest::binary()>>, secret)
defp jwk(_alg, key) when is_binary(key)
defp jwk(_alg, key) when is_map(key)
(assent) lib/assent/jwt_adapter/jose.ex:24: Assent.JWTAdapter.JOSE.jwk/2
(assent) lib/assent/jwt_adapter/jose.ex:46: Assent.JWTAdapter.JOSE.verify/3
(assent) lib/assent/strategies/apple.ex:108: Assent.Strategy.Apple.get_user/2
(assent) lib/assent/strategies/oauth2.ex:237: Assent.Strategy.OAuth2.fetch_user/3
(assent) lib/assent/strategies/oauth2/base.ex:69: Assent.Strategy.OAuth2.Base.callback/3
The error is caused by a nil parameter being passed for the public key in the following line:
assent/lib/assent/strategies/apple.ex
Line 107 in 50f49b4
I was able to work around the issue by providing the Apple Public Key from https://appleid.apple.com/auth/keys as a configuration parameter as follows:
def get_user(config, token) do
public_key = Config.get(config, :public_key, nil)
with {:ok, jwt} <- Helpers.verify_jwt(token["id_token"], public_key, config) do
{:ok, jwt.claims}
end
end
with the :public_key specified in my config as follows:
config :my_app, :pow_assent,
providers: [
apple: [
strategy: Assent.Strategy.Apple,
client_id: System.get_env("APPLE_CLIENT_ID"),
team_id: System.get_env("APPLE_TEAM_ID"),
private_key_id: System.get_env("APPLE_PRIVATE_KEY_ID"),
private_key: System.get_env("APPLE_PRIVATE_KEY"),
jwt_adapter: Assent.JWTAdapter.JOSE,
public_key: %{
"kty" => "RSA",
"kid" => "AIDOPK1",
"use" => "sig",
"alg" => "RS256",
"n" =>
"lxrwmuYSAsTfn-lUu4goZSXBD9ackM9OJuwUVQHmbZo6GW4Fu_auUdN5zI7Y1dEDfgt7m7QXWbHuMD01HLnD4eRtY-RNwCWdjNfEaY_esUPY3OVMrNDI15Ns13xspWS3q-13kdGv9jHI28P87RvMpjz_JCpQ5IM44oSyRnYtVJO-320SB8E2Bw92pmrenbp67KRUzTEVfGU4-obP5RZ09OxvCr1io4KJvEOjDJuuoClF66AT72WymtoMdwzUmhINjR0XSqK6H0MdWsjw7ysyd_JhmqX5CAaT9Pgi0J8lU_pcl215oANqjy7Ob-VMhug9eGyxAWVfu_1u6QJKePlE-w",
"e" => "AQAB"
}
]
]
Hard coding the Apple public key is just a work around to get me up and running. I notice that the Ueberauth Apple strategy fetches the Apple public key during the verification phase and I guess the Assent Apple strategy should do the same?
The SSL verification is optional, but I believe a warning each time an insecure request is made (wether http or no cert verification).
Ref: https://openid.net/specs/openid-connect-core-1_0.html#SelfIssued
Ref: https://elixirforum.com/t/using-openid-connect-in-production-how-to-do-full-security-checks/28331/7
This would require implicit grant flow support. I've tested this a bit and will put up a draft PR soon.
Hi,
Using assent to authenticate through oauth2 on a micro-app that had no ecto backup nor need to record user information past authorization, I encountered an error after the built succeed:
web_1 | ** (exit) an exception was raised:
web_1 | ** (UndefinedFunctionError) function :httpc.request/4 is undefined (module :httpc is not available)
web_1 | :httpc.request(:post, {'https://api.intra.42.fr/oauth/token', [{'User-Agent', 'Assent-0.1.16'}], 'application/x-www-form-urlencoded', 'code=d44d4959376eb30953852cc66cb4ebce50c4018dfda2dc79ebd26414bcac3ab2&redirect_uri=http%3A%2F%2Flocalhost%3A4000%2Fsession%2Fcallback&grant_type=authorization_code&client_id=54d568770a5f2984fdacf76bcf38d469edbe71b55ccd050dd83a63fd94f0ac6b&client_secret=b237063058109ba31701030463a9a77616fecab6b866e53f1b50e1c03da9d3e5'}, [], [])
web_1 | (assent) lib/assent/http_adapter/httpc.ex:25: Assent.HTTPAdapter.Httpc.request/5
web_1 | (assent) lib/assent/strategy.ex:42: Assent.Strategy.request/5
web_1 | (assent) lib/assent/strategies/oauth2.ex:250: Assent.Strategy.OAuth2.grant_access_token/3
web_1 | (assent) lib/assent/strategies/oauth2.ex:129: Assent.Strategy.OAuth2.callback/3
# ... here be where the binding was used in my app
That happened during the callback of the oauth2 transaction, and completely baffled me. It looked like something like a missing dependency or something, yet I did not see anything like this in assent's docs, and when I googled it, it looked exactly like the inets
lib was missing...
I finally figured out how to fix this, adding inets
to the extra_applications:
# in app/mix.exs
def application do
[
# ...
extra_applications: [
# ...
:inets
]
]
end
...aaaand... that worked.
Maybe it should be noted in the installation docs that inets
is necessary to be started for it to work. I'm willing to make a PR explaining it, but I'd like for someone knowing assent from the inside out to explain why and in which cases it's necessary to have inets
as a dependency first (so I don't mislead others either).
So, there. Thank you for that awesome lib by the way.
The map returned by Assent.JWTAdapter.AssentJWT.verify/3
may have the verified?
-key set to an {:error, _}
tuple, which may cause issues when doing a simple check for trueness.
token = "..."
secret = %{...}
{:ok, details} = Assent.JWTAdapter.AssentJWT.verify(token, secret, [json_adapter: Jason])
if details.verified? do
IO.puts("Everything is cool!")
else
IO.puts("Verification failed.")
end
You may see Everthing is cool!
although an error occurred, because verified?
contains an {:error, _}
tuple. Here's an example of where the tuple can come from:
assent/lib/assent/jwt_adapter/assent_jwt.ex
Line 171 in d2c4675
Sadly, I cannot provide you with the token and secret I stumpled upon that error, but by looking at the code, you already see that the error-tuple is a possible value for the verified?
-field.
warning: :crypto.hmac/3 is undefined or private. Did you mean one of:
* mac/3
* mac/4
* macN/4
* macN/5
lib/assent/strategies/facebook.ex:122: Assent.Strategy.Facebook.appsecret_proof/2
warning: :crypto.hmac/3 is undefined or private. Did you mean one of:
* mac/3
* mac/4
* macN/4
* macN/5
lib/assent/strategies/oauth.ex:173: Assent.Strategy.OAuth.gen_signature/6
warning: :crypto.hmac/3 is undefined or private. Did you mean one of:
* mac/3
* mac/4
* macN/4
* macN/5
lib/assent/jwt_adapter/assent_jwt.ex:43: Assent.JWTAdapter.AssentJWT.sign_message/3
sorry
Hey, first of all, thanks for the library, really good, but I have one question:
Do you think it could make sense to use Tesla as the HTTP abstraction so the library could use any of the Tesla adapters out there? Or we could have a an Assent.HTTPAdapter for Tesla, but then we would have adapter of the adapter xD.
Tesla currently have adapters for Finch, Gun, hackney, httpc, ibrowse and Mint.
Tesla also have a test adapter which might come in handy.
Hi, and thanks for building and maintaining this 👋.
In the configuration documentation for OIDC, :openid_configuration
isn't strictly required since it can be fetched from :openid_configuration_uri
if it isn't defined. Similarly, :openid_configuration_uri
is also optional, since it defaults to /.well-known/openid-configuration
based on :site
.
Both authorize_url/1
and callback/3
work this way by calling openid_configuration/1
. However, fetch_user/2
, fetch_userinfo/2
, and validate_id_token/2
are using Config.fetch/2
to resolve configuration, so they aren't getting it dynamically.
Should these work consistently? I'm a bit new to both Elixir and OIDC, so it's quite possible my understanding is off here.
If the intent is to have them all get :openid_configuration
dynamically, I'm happy to try submitting a PR.
Thanks for your time!
Right now assent assumes that the client will pass code
in parameter list in the callback phase. There are cases, though, when the client has an access token already (assent does not need to fetch it and does not have the means to do so). Would it be possible and desirable to accept access tokens as well in OAuth2 strategy.
My specific use case is Facebook login on mobile devices where client side libraries only allow to fetch the access token straight away.
Based on pow-auth/pow_assent#89
So the current implementation of
PowAssent.HTTPAdapter.Mint
doesn't pool HTTP/2 connections. For it to do that, I'll need to set it up as a GenServer. This way all connections can be kept open and all requests can be faster and more efficient. As new requests are coming in, the connections will be created if they don't exist in the GenServer state.I haven't decided yet if the GenServer should be an extra layer on top of the current implementation so they work in parallel, or it should just replace it entirely and you are required to start it up to use Mint. I feel the latter is the better choice, since there is not really much of a point in using Mint without connection pool.
Any feedback/thoughts are welcome, I only have a superficial understanding of HTTP/2 🙂
There is very weak JWT parsing in the current library. It would probably be best if there actually is some validation done on the JWT instead. It should either be a built-in module, or a third-party module that can be changed like with :http_adapter
.
I realize that the typespec for normalize/2
belonging to the OIDC strategy is different than the one described in the docs, and the OAuth2 one, and it is making my dialyzer fail.
I believe it should be changed to
@callback normalize(Keyword.t(), map()) :: {:ok, map()} | {:ok, map(), map()} | {:error, term()}
to allow claims that don't conform to the OIDC spec
Hello and thanks for creating this great library 👍
Is there any interest in a LinkedIn OAuth strategy, something akin to the Ueberauth.LinkedIn strategy?
When using the "name"
scope with sign-in with Apple, it doesn't seem like the "user"
map that contains "firstName"
and "lastName"
is decoded, or added to the token
map in OAuth2.callback/3
. This means that when Strategy.Apple
attempts to merge the name params into the other user params, nothing is there. In my application this results in "given_name"
and "family_name"
being absent when trying to insert a new user into the database.
I was able to fix this in my project by decoding the "user"
map in OAuth2.callback/3
, and assigning it to token
before passing it off to fetch_user_with_strategy
as follows:
@impl true
@spec callback(Config.t(), map(), atom()) :: {:ok, %{user: map(), token: map()}} | {:error, term()}
def callback(config, params, strategy \\ __MODULE__) do
with {:ok, session_params} <- Config.fetch(config, :session_params),
:ok <- check_error_params(params),
{:ok, code} <- fetch_code_param(params),
{:ok, redirect_uri} <- Config.fetch(config, :redirect_uri),
:ok <- maybe_check_state(session_params, params),
- {:ok, token} <- grant_access_token(config, "authorization_code", code: code, redirect_uri: redirect_uri) do
+ {:ok, token} <- grant_access_token(config, "authorization_code", code: code, redirect_uri: redirect_uri),
+ token <- maybe_add_user_callback_params(config, token, params) do
fetch_user_with_strategy(config, token, strategy)
end
end
+ defp maybe_add_user_callback_params(config, token, %{"provider" => "apple", "user" => user}) do
+ Map.put(token, "user", Config.json_library(config).decode!(user))
+ end
+ defp maybe_add_user_callback_params(_config, token, _params), do: token
Does this seem right? I've looked pretty closely at the code paths involved, and don't see any other place where this information seems to be handled. Happy to open a PR if this is a real issue, and if the fix seems appropriate!
I am trying to use PowAssent with OAuth2 strategy against an ADFS-provider and it's almost working, but even though I can see the access_token as a param in the request, something is not quite right yet. Probably I am just missing something relevant. I thought, I'd report just in case anyone else faces this (ungoogleable) error code in the subject.
Glad for any pointers, let me know, if you need more info.
Thank you and cheers!
P.S. I did this:
PPS: I realize now that this might belong into the Assent repo 🤕
scope "/" do
pipe_through :skip_csrf_protection
post "/auth/:provider/callback", PowAssent.Phoenix.AuthorizationController, :callback
end
================================================
warning: This request will NOT be verified for valid SSL certificate
(assent) lib/assent/http_adapter/httpc.ex:22: Assent.HTTPAdapter.Httpc.request/5
(assent) lib/assent/strategy.ex:42: Assent.Strategy.request/5
(assent) lib/assent/strategies/oauth2.ex:222: Assent.Strategy.OAuth2.get_access_token/2
(assent) lib/assent/strategies/oauth2.ex:119: Assent.Strategy.OAuth2.callback/3
(assent) lib/assent/strategies/oauth2/base.ex:69: Assent.Strategy.OAuth2.Base.callback/3
(pow_assent) lib/pow_assent/plug.ex:74: PowAssent.Plug.callback/4
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:39: PowAssent.Phoenix.AuthorizationController.process_callback/2
(pow) lib/pow/phoenix/controllers/controller.ex:99: Pow.Phoenix.Controller.action/3
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.action/2
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.phoenix_controller_pipeline/2
(phoenix) lib/phoenix/router.ex:288: Phoenix.Router.call/2
(my_app) lib/my_app_web/endpoint.ex:1: MyAppWeb.Endpoint.plug_builder_call/2
(my_app) lib/plug/debugger.ex:122: MyAppWeb.Endpoint."call (overridable 3)"/2
(my_app) lib/my_app_web/endpoint.ex:1: MyAppWeb.Endpoint.call/2
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4
(cowboy) c:/src/my_app/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy) c:/src/my_app/deps/cowboy/src/cowboy_stream_h.erl:320: :cowboy_stream_h.execute/3
[error] #PID<0.1578.0> running SmartpowerWeb.Endpoint (connection #PID<0.1549.0>, stream id 5) terminated
Server: localhost:4200 (http)
Request: POST /auth/oauth2/callback
** (exit) an exception was raised:
** (Assent.RequestError) Server responded with status: 400
Headers:
cache-control: no-store
date: Mon, 11 Nov 2019 21:27:16 GMT
pragma: no-cache
server: Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0
content-length: 146
content-type: application/json;charset=UTF-8
Body:
%{"error" => "invalid_request", "error_description" => "MSIS9691: Received invalid OAuth request. The Basic Authorization header must be Base64 encoded."}
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:190: PowAssent.Phoenix.AuthorizationController.handle_strategy_error/1
(pow) lib/pow/phoenix/controllers/controller.ex:99: Pow.Phoenix.Controller.action/3
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.action/2
(pow_assent) lib/pow_assent/phoenix/controllers/authorization_controller.ex:1: PowAssent.Phoenix.AuthorizationController.phoenix_controller_pipeline/2
(phoenix) lib/phoenix/router.ex:288: Phoenix.Router.__call__/2
(myapp) lib/myapp_web/endpoint.ex:1: MyAppWeb.Endpoint.plug_builder_call/2
(myapp) lib/plug/debugger.ex:122: MyAppWeb.Endpoint."call (overridable 3)"/2
(myapp) lib/myapp_web/endpoint.ex:1: MyAppWeb.Endpoint.call/2
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4
(cowboy) c:/src/myapp/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy) c:/src/myapp/deps/cowboy/src/cowboy_stream_h.erl:320: :cowboy_stream_h.execute/3
(cowboy) c:/src/myapp/deps/cowboy/src/cowboy_stream_h.erl:302: :cowboy_stream_h.request_process/3
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
I see WIP support for PKCE flows in danschultzer/ex_oauth2_provider#91.
Any thoughts on integrating PKCE into Assent?
Hello!
When a user uses the "Sign in with Slack" functionality to authenticate, Slack always "asks" for permission. That confuses users. Usually the identity provider asks once and just redirects on subsequent sign ins.
I've asked Slack Support about it and they said:
It is the case that the prior SIWS (Sign in With Slack) functionality (which used identity.* scopes) asks for permission each time users accesses your resources.
However, we have updated this to a flow that's based on the OpenID Connect standard, and uses the openid scope. You can read more about that on the following updated SIWS page:
I just wanted to track it here first. Probably I'll have some time to dig deeper about that in Assent. Any feedback is welcome :)
Based on #18 (comment)
These strategies pulls claims from the id_token
JWT, but doesn't verify them. It would be safer to always verify the tokens even if the full OAuth 2 code flow is used.
Based on pow-auth/pow_assent#93
iOS 13 has introduce Apple OAuth2 auth. It's just OAuth 2 with JWT so it'll be easy to implement. However, seems like Apple recommends using their JS for the request phase so maybe that is something that should be possible to configure with PowAssent?
I am getting a 400 when sending requests to login.microsoftonline.com
while using the Finch adapter.
%{
name: InternalFinch,
request: %Finch.Request{
body: nil,
headers: [{"User-Agent", "Assent-0.2.9"}],
host: "login.microsoftonline.com",
method: "GET",
path: "/organizations/v2.0/.well-known/openid-configuration",
port: 443,
private: %{},
query: nil,
scheme: :https,
unix_socket: nil
},
result: {:ok,
%Finch.Response{
body: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">\r\n<HTML><HEAD><TITLE>Bad Request</TITLE>\r\n<META HTTP-EQUIV=\"Content-Type\" Content=\"text/html; charset=us-ascii\"></HEAD>\r\n<BODY><h2>Bad Request - Invalid Header</h2>\r\n<hr><p>HTTP Error 400. The request has an invalid header name.</p>\r\n</BODY></HTML>\r\n",
headers: [
{"content-type", "text/html; charset=us-ascii"},
{"date", "Mon, 11 Mar 2024 15:55:17 GMT"},
{"connection", "close"},
{"content-length", "339"}
],
status: 400
}},
}
I'm not sure if Microsoft is flagging this User-Agent as a bot, or there's actually an issue with the payload, but here are the only headers that seem to be sent in the request:
headers: [{"User-Agent", "Assent-0.2.9"}],
Do we have any control over the headers sent in the payload while using an http adapter? I'd like to try and debug if adding/removing this header can make a difference.
Here are my dependencies:
{:assent, "~> 0.2.9"},
{:finch, "~> 0.16"},
any help would be much appreciated!
Currently, assent has support for Google Sign in for the web, the client sends the code and scope and the strategy retrieves from google the JWT with the data.
This works fine for the web, but not so much for mobile apps where normally the client will retrieve the JWT (id token) directly and the server job is to validate it.
Since I need exactly this case, I created a new strategy for it, you can add it to Assent if you want, and also I would appreciate it if you can take a look and see if there is some flaw in the logic.
The strategy itself is very simple, you simply send the id_token to id and it will validate it.
defmodule Core.Identity.GoogleSignIn.Strategy do
@moduledoc false
alias Core.Identity.GoogleSignIn.JWTManager
@behaviour Assent.Strategy
@impl true
def callback(_, params) do
%{id_token: id_token} = params
case JWTManager.verify_and_validate(id_token) do
{:ok, user} -> {:ok, %{user: user}}
{:error, _} -> {:error, :invalid_token}
end
end
@impl true
def authorize_url(_), do: throw("not implemented")
end
For validation, here are my modules:
defmodule Core.Identity.GoogleSignIn.JWTVerifyHook do
@moduledoc false
use Joken.Hooks
@impl true
def before_verify(_, {jwt, %Joken.Signer{}}) do
with {:ok, %{"kid" => kid}} <- Joken.peek_header(jwt),
{:ok, algorithm, key} <- GoogleCerts.fetch(kid) do
{:cont, {jwt, Joken.Signer.create(algorithm, key)}}
else
_ -> {:halt, {:error, :no_signer}}
end
end
end
defmodule Core.Identity.GoogleSignIn.JWTManager do
@moduledoc false
alias Core.Identity.GoogleSignIn.JWTVerifyHook
use Joken.Config, default_signer: nil
add_hook(JWTVerifyHook)
@iss "https://accounts.google.com"
@impl true
def token_config do
default_claims(skip: [:aud, :iss])
|> add_claim("iss", nil, fn iss -> iss == @iss end)
|> add_claim("aud", nil, fn aud -> aud == aud() end)
end
defp aud do
Application.fetch_env!(:core, :pow_assent)
|> Keyword.fetch!(:providers)
|> Keyword.fetch!(:google_sign_in)
|> Keyword.fetch!(:client_id)
end
end
Hello Dan & Pow crew!
I've found tremendous value in this library and I've just realized I should be pushing for us to sponsor the project!
Auth0 has notified me about a deprecation in their API for fixed length access tokens and authorization codes. They're apparently doing a hard cut-over on April 12th. At that point, I expect things will stop working properly as my Auth0 log says the following when I log in:
Fixed Length of Access Token & Authorization Code: This feature is being deprecated. Please see https://auth0.com/docs/product-lifecycle/deprecations-and-migrations#opaque-access-token-for-userinfo for more information.
What's the best course of action to make sure I remain compatible? I'm going to need to dig in deeper, but this is a bit foreign to me. I could certainly use a hand!
And thank you so much for the time & energy put into the pow/assent ecosystem.
Adam
The possible return values of Assent.JWTAdapter.AssentJWT.verify/3
do not match the callback definition of Assent.JWTAdapter.verify/3
🤔
Here is the callback definition:
assent/lib/assent/jwt_adapter.ex
Line 25 in d2c4675
Calling Assent.JWTAdapter.AssentJWT.verify/2
can also return just :error
😲 Have a look into the example below:
token = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImV4YW1wbGUiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJhc3NlbnQtaXNzdWUiLCJleHAiOjE3MTk0ODk5MDcsInN1YiI6IjQyIn0.o3Lijaa_Q5m1Tr7A6myopsdtO771SlVu9rK-ElIqdYcj5eo5PochP3cqG7NFw76TqyRMdNwkr-OQevAWUbcireZ-dSKtkhtYm91M2sVM_RI5s7LTfdbUTHEleCAg_x0pC1mkDRmKSKBPuooEKypIl6P6ME0GogC_4SthzYRx3gks6m9TNI8wCzRhOaGuLEvnOm8KoQXpreVLfibe_C_v30AiJVzxMoqskQKJ9hagE34I9SB6ut3_ZsczMisjXe5cGLcsWSctAoi-JaIqUk3pMyfgUVVvt8ZzbV2LvqPz2O1vOAT-QDui68szYFAJh9IaNbwVC9QdLmthdg01DLYrA"
secret = %{
"alg" => "RS256",
"e" => "AQAB",
"kid" => "example",
"kty" => "RSA",
"n" => "g5IE_tFgft5wRYPwivPY4QpNc6IpbZv5w24tW2rKdS74ntwhPQo38yahAOUujTAbpUvN3motDtJOkjov9O6fxhFkjOEA4zxXFGxHWyMwloRjNen9uScbi88EuVaSuTWKoq4C9FE650222QrtU0SImMSgi166sbTbi5bvS9hanSphksmw8vdVff56aFE5jOpVXNEoFoj3CFTRfesIhht9qXJp-HFbbSkDcyeQ1Y5rv5nzKQXMONTxxhV-qaJ03BNLxFVOP9eqeVTUHQoQ262qpbz-3qRWxxqy5Q2V0g4yk-IJPV2u6yNd5SojsRK3V5YIC3b0_VuDXN_we0o-sOjESQ",
"use" => "sig"
}
Assent.JWTAdapter.AssentJWT.verify(id_token, secret, [json_library: Jason])
The :error
is caused by a broken token
I passed in. When using a valid token (see below), you get an {:ok, _}
tuple.
eyJhbGciOiJSUzI1NiIsImtpZCI6ImV4YW1wbGUiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJhc3NlbnQtaXNzdWUiLCJleHAiOjE3MTk0ODk5MDcsInN1YiI6IjQyIn0.Zo3Lijaa_Q5m1Tr7A6myopsdtO771SlVu9rK-ElIqdYcj5eo5PochP3cqG7NFw76TqyRMdNwkr-OQevAWUbcireZ-dSKtkhtYm91M2sVM_RI5s7LTfdbUTHEleCAg_x0pC1mkDRmKSKBPuooEKypIl6P6ME0GogC_4SthzYRx3gks6m9TNI8wCzRhOaGuLEvnOm8KoQXpreVLfibe_C_v30AiJVzxMoqskQKJ9hagE34I9SB6ut3_ZsczMisjXe5cGLcsWSctAoi-JaIqUk3pMyfgUVVvt8ZzbV2LvqPz2O1vOAT-QDui68szYFAJh9IaNbwVC9QdLmthdg01DLYrA
I'm currently struggling to find a way how to map additional claims from Azure AD provider into user_identity
changeset.
These are the claims that Azure AD returns:
claims: %{
"aud" => "93572ac3-0740-4aa5-ad35-18ba25d5fe22",
"email" => "[email protected]",
"exp" => 1642465568,
"iat" => 1642461668,
"iss" => "https://login.microsoftonline.com/6ee623a2-0b05-4ea4-b931-79c555955cb1/v2.0",
"name" => "Moravec Albert",
"nbf" => 1642461668,
"oid" => "09cbdc15-ccf1-43e9-a2fb-8e9d9513d5cc",
"preferred_username" => "[email protected]",
"rh" => "0.AToAoiPmbgULpE65MXnFVZVcscMqV5NAB6VKrTUYuiXV_iI6AO4.",
"roles" => ["administrator", "manager"],
"sub" => "1ct7-HTE7-CM5h5H7009_9lRRLdHiAHt1hY30ogqji0",
"tid" => "6ee623a2-0b05-4ea4-b931-79c555955cb1",
"uti" => "5aLPSh0CRUW_doLHsZxjAA",
"ver" => "2.0"
}
Since standard OpenID Connect mapping is used, all of the claims except the standardized ones are thrown away. Is there a way to override this behavior?
I personally expected this to be doable at least on the Strategy
level by customizing the normalize/2
, but the user there is already stripped of all the claims.
[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
Hello there, would you mind if I added strategy for Yandex OAuth? It might be useful for someone who uses that provider.
Telegram offers a convenient way of authenticating users by allowing them to enter their Telegram-linked phone number and confirm the request directly in the Telegram messenger app without a password.
However, they don’t support the traditional method of redirecting to their OAuth server to enter credentials. Instead, it is necessary to include their JS library on the page and either use an embedded iframe with a standard button (with limited styles) or - via an undocumented method - directly call the library's auth(callback)
function with a callback to get the results. The official login widget also supports the redirect mode to a provided callback URL. This means that the authorize_url/1
call is useless for this implementation (more on this later).
Additionally, Telegram has published the Web Mini App API. This API allows direct interaction with many internal Telegram features. The Mini Web App is intended to be opened directly from the messenger app and to work inside the app.
To authenticate a user of a web app, Telegram sends a URL-encoded query string (protected by a hash) that contains all the initial data when opening the web app. This string doesn’t pass through a WebView instance and should be collected inside the frontend and sent to the backend for authentication. The backend needs to check the data’s authenticity by calculating the hash of the string and comparing it with the provided one, as well as validating the authentication date.
#152 implements the strategy.
Returning to the authorization_url/1: it is possible to use it to create a script to embed in the HTML page. The generator, depending on config parameters, can then generate different embedding options. However, this contradicts the direct meaning of authorization_url
call.
WDYT?
I'm sorry, I know that this is not really directly related to assent.
The Facebook strategy requires an authorization code for the callback.
In this issue you say that "The Facebook strategy docs now highlights how to fetch the code client side to submit server side".
Our problem is that we are using https://github.com/facebook/react-native-fbsdk to implement the frontend facebook auth in react native. So we I don't think we can use the JS sdk to get the signed request and get the authorization code.
Please could you point me in the right direction on how to get the code from the accessToken in this situation?
Hey there,
We would like to pass the state
parameter:
assent/lib/assent/strategies/oauth2.ex
Line 101 in 61cf499
We want to marshal some JSON payload as base64 to pass a state from the client into the oauth2 flow.
Would you be willing to add the feature?
It looks like the result for /me
for Facebook is returning a JSON payload but the payload is never decoded and passed to normalize where it fails. I don't believe this a configuration issue but I could be wrong. I've included my config and some of the dbg trail below:
config #=> [
strategy: Assent.Strategy.Facebook,
base_url: "https://graph.facebook.com/v4.0",
authorize_url: "https://www.facebook.com/v4.0/dialog/oauth",
token_url: "/oauth/access_token",
user_url: "/me",
authorization_params: [scope: "email"],
user_url_request_fields: "email,name,first_name,last_name,middle_name,link",
auth_method: :client_secret_post,
session_params: %{state: "b12f74c55b98953535c75f3143cd8d4e475f8c3b2a"},
redirect_uri: "https://local.host:5301/auth/facebook/callback",
client_id: "<redacted>",
client_secret: "<redacted>",
redirect_path: "/auth/facebook/callback"
]
|> process_user_response() #=> {:ok,
"{\"email\":\"doneth7\\u0040me.com\",\"name\":\"John Doneth\",\"first_name\":\"John\",\"last_name\":\"Doneth\",\"id\":\"7425858337461382\"}"}
** (FunctionClauseError) no function clause matching in Access.get/3
(elixir 1.16.1) lib/access.ex:307: Access.get("{\"email\":\"doneth7\\u0040me.com\",\"name\":\"John Doneth\",\"first_name\":\"John\",\"last_name\":\"Doneth\",\"id\":\"7425858337461382\"}", "id", nil)
(assent 0.2.9) lib/assent/strategies/facebook.ex:92: Assent.Strategy.Facebook.normalize/2
assent/lib/assent/strategies/google.ex
Line 41 in e031dca
user
map is returning email_verified
instead of verified_email
, so the strategy now is always returning unverified email.
Hello! I'm pretty new to Elixir so forgive me if this has an easy answer. I'm creating a custom OIDC provider (Netsuite) that issues 2 audiences in a list, one of which is the client ID.
In the oidc.ex, audience validation simply matches what's returned in the claim with the client_id but unfortunately this always produces the "Invalid audience" error.
How would I go about filtering the data so that I could either remove the other audience or add it to what's being matched? I'm trying to follow along with the Apple OIDC provider but can't quite make sense of it.
I'm implementing a provider, which needs an aditional body parameter when calling the token
endpoint.
in order to override &Assent.Strategy.callback/2
, i think that the additional defoverridable Helpers
(or defoverridable callback: 2
) is needed, otherwhise the implementation in my custom module is ignored.
** Should this overridable definition not be included in the __using/2
definition of Assent.Strategy.OAuth2.Base
?
The use definition defines these behavoiurs:
assent/lib/assent/strategies/oauth2/base.ex
Lines 44 to 45 in 4457d3e
The only defoverridable in the Assent.Strategy.OAuth2.Base.__using__/1
Macro is this one:
In order to override the callback/2
in my implementation module i need to do this:
defmodule CanteAuth.Assent.Strategy.Anaf do
use Assent.Strategy.OAuth2.Base
#Shouldn't this be in Assent.Strategy.OAuth2.Base.__using__/1?
defoverridable Helpers
...
@impl Helpers
def callback(config, params) do
Is the macro Assent.Strategy.OAuth2.Base.__using__/1
really missing the line
defoverridable Helpers
or am I missing something obvious, for overriding functions imported from Assent.Strategy
?
Thank you for this wonderful library! ❤️
Hi guys,
While implementing the endboss, aka sign in with Apple I ran into some issues.
The docs in Assent.Strategy.Apple
specifically talk about the JS SDK, but I couldn't figure out how to get the state to be passed
in and read back correctly.
In the end I resorted to just using the Routes.pow_assent_authorization_url/3
, which worked like a charm.
Long story short, it would be great to give people a pointer to just using the regular /auth/apple/new
flow, especially since the apple docs only talk about their JS SDK as well.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.