Skip to content
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

a state param #149

Open
nbw opened this issue Nov 15, 2021 · 5 comments
Open

a state param #149

nbw opened this issue Nov 15, 2021 · 5 comments

Comments

@nbw
Copy link

nbw commented Nov 15, 2021

Responding to @yordis's comment in this thread

Feature:

It would be nice to have the ability to use a "state" param, whilst maintaining CSRF protection changes mentioned below.

Context:

Prevent CSRF Using state Parameter was fixed by 136 in which the state parameter was used to satisfy the OAuth 2.0 specification is in CSRF protection specification.

Before the change, ueberauth_facebook supported a state parameter, which has now been removed by this PR.


For extra context, I thought it would also be worth mentioning my actual use-case since we use the state param for ueberauth_facebook. We use the state parameter to distinguish between: signup, login, and authorizing a new instagram account.

  • Sign up and login are fairly trivial to distinguish without the state parameter (check if the account already exist or not, basically)

  • Authorizing a new instagram account is trickier because a user can authorize an instagram account belonging to email "A" on facebook/instgram, but they're logged into a user with email "B" on our app. This requirement exists because businesses often manage multiple instagram accounts and so we can't guarantee that the email used for instagram is the same as the email they use for their account on our app. To remedy this, we pass a signature that will identify the user when being redirected from the auth flow.

This is the way we solve it, but if there's a better way then I'm all ears.

@Hanspagh
Copy link
Contributor

Hi @nbw.
I have been reading about this lately, and found this documentation from Auth0 https://auth0.com/docs/secure/attack-protection/state-parameters

It seems to be valid usecase to use the state, but you should rather use the state nonce as a look up value. Maybe we should provide some funtionality to get the state noce stored in the cookie

@yordis
Copy link
Member

yordis commented Jan 25, 2022

Take it with a grain of salt, because I never used the state that way, so please help me to help you.

Authorizing a new instagram account is trickier because a user can authorize an instagram account belonging to email "A" on facebook/instgram, but they're logged into a user with email "B" on our app.

When you are Connecting you have an authenticated user. While Sign/Login there is no authenticated user until you successfully find or create a user and respond with a session.

So, would it make sense to

  1. Check if the user authenticated
    1.1) Get the authenticated account.
    1.2) Trying to add the account to the list of provider accounts of that user
  2. If the user is not authenticated,
    1.1) Find or Create based on the email from the provider account.

No? 🤔

@nbw
Copy link
Author

nbw commented Jan 25, 2022

No worries. If I could not use the state param then that'd be better for me, so. I'm totally open to solutions.

[edit: updating this message because the markdown formatting is a bit weirdy

The assumption I making is that the only way to identify the user is by their email which is returned by the auth, but if there's a better way then I'm all for it (%UeberAuth.Auth{info: %{email: email}).


  1. Sign up

Doesn't require a state param. Like you said, you find or create based on the email from the provider account.


  1. Sign in

Doesn't require a state param. You just check that you have an account with that email already.


  1. Link an Instagram account

So let's say in our business case we have a user who signed up using facebook auth with their email xyz@test.com, for example.

Then they link an Instagram account to their account on our system. I'm not talking about a personal instagram account, but instead a business account or creator account that might be under a different email. Our app is specifically targeting users with Instagram Business accounts. We can't guarantee that the email they signed up with is the email they use for their instagram account.

So the user authenticates their Instagram account, which we'll say is under the email abc@test.com (different than the one they signed up with). When the auth succeeds and they're redirected back to our site. How should I tie the response auth to an account on our system if they not under the same email?

One option would be to collect that other email, somehow. One option could be a cookie, perhaps? Right now I've passed in a temporary signature through the state param which I use to tie them back together on return.

@yordis
Copy link
Member

yordis commented Jan 25, 2022

One option could be a cookie, perhaps?

In the worst case, yes, you would use cookies related to your business use case instead of mixing it with the state since that has a technical concern from auth perspective.

@teamon
Copy link

teamon commented May 30, 2024

In case someone is looking for a cookie/session-based solution it can be done like this:

defmodule My.OAuthController do
  # ...
  
  plug :store_return_to_in_session
  plug Ueberauth
  
  # ...

  defp store_return_to_in_session(conn, _) do
    {return_to, params} = Map.pop(conn.params, "return_to")

    conn
    |> Map.put(:params, params)
    |> then(fn conn ->
      if return_to do
        put_session(conn, :user_return_to, return_to)
      else
        conn
      end
    end)
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants