trivialcase

trivialcase

I have a piece of code that gets executed on successful user signin, and everything seems to work fine, except that one of my assigned variables isn’t getting assigned by the code, but it works fine when I do it while debugging with pry…

Here is my code:

case TokenAuthentication.verify_token_value(token) do
  {:ok, user} ->
    conn
    |> put_session(:user_id, user.id)
    |> configure_session(renew: true)
    |> put_flash(:info, "Congratulations, #{user.first_name}, you were signed in successfully.")
    |> assign(:current_user, user)
    IEx.pry
    |> redirect(to: page_path(conn, :index))

and when I pry I have

assigns: %{current_user: nil}

but then I do assign(conn, :current_user, user) at the prompt and I get

assigns: %{current_user: %Myapp.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    auth_tokens: #Ecto.Association.NotLoaded<association :auth_tokens is not loaded>,
    email: "test@test.com", first_name: "Test", id: 20,
    inserted_at: ~N[2017-05-09 13:06:32.374191], last_name: "McTest",
    password: nil, password_confirmation: nil,
    password_hash: "$2b$12$v8zTVSz0TGJ6COKlGb0TY.pbg3lnpJMZprmjDz3OS6s5aZWIDgsaC",
    updated_at: ~N[2017-05-09 13:06:32.374206]}}

as expected. I know that Elixir shouldn’t have side effects, so how is my running it at the prompt different?

Showing Posts 1 to 10

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Your code isn’t quite doing what you think it is. Here it is formatted better:

    conn
    |> put_session(:user_id, user.id)
    |> configure_session(renew: true)
    |> put_flash(:info, "Congratulations, #{user.first_name}, you were signed in successfully.")
    |> assign(:current_user, user)
    # everything prior to this line has now been thrown away, you didn't bind it to anything

    IEx.pry
    |> redirect(to: page_path(conn, :index))

If I had to guess IEx.pry will return whatever it is you’ve last written in it. So if you assign a conn, that assigned conn will get passed through to the redirect function.

Aetherus

Aetherus

Remember that all data structures in Elixir are immutable, so is a %Plug.Conn{}.

Plug.Conn.assign/3 always returns a new %Plug.Conn{}. So your code should be

conn = conn
       |> put_session(:user_id, user.id)
       |> configure_session(renew: true)
       |> put_flash(:info, "Congratulations, #{user.first_name}, you were signed in successfully.")
       |> assign(:current_user, user)

IEx.pry

redirect(conn, to: page_path(conn, :index))

Note that the local variable conn is reassigned.

trivialcase

trivialcase OP

Exactly right, thank you, I think I should have seen that.

If you don’t mind indulging me a little further, the reason I am debugging this is that the current_user never makes it to my template. Here’s my authentication scheme:

(1) User signs up, generate a jwt using Guardian.encode_and_sign, send a verification email to the new user with a link containing the token

(2) User clicks the link, the jwt is checked by Guardian.decode_and_verify, then that code above is executed

Now that I think about it, the problem seems to be that the redirect sends the connection back through the router where it hits my pipeline, which resets current_user anyway:

pipeline :browser_session do
  plug Guardian.Plug.VerifySession
  plug Guardian.Plug.LoadResource
  plug Myapp.CurrentUser # gets current_user using Guardian.Plug.current_resource
end

But I’m guessing that this is the problem, somehow the non-Plug functionality of Guardian and the Plug stuff don’t work together. I don’t suppose anyone knows off-hand how these pieces of Guardian should work together, i.e. should I somehow be doing a Guardian.Plug.sign_in for the user once their link is verified? I am a little worried that the token from the email verification process is still floating around out there and might muck up the works.

Aetherus

Aetherus

I’m not familiar with Guardian so excuse me if I’m wrong.

Since you’re using token authentication, the token should be maintained by the client side code (e.g. javascript on the browser side). The client should carry the token on every request whenever the token is available.

However, redirect is a two-step action:

  1. the browser receives a response with status code 302 and a Location header, which contains a URL.
  2. the browser sends another GET request immediately to the URL in Location header.

Unfortunately, you can’t control the second step. You can’t add headers to it, you can’t specify the HTTP method, you can’t add cookie to it, and you can’t attach token to it. I think this is the reason why you lose the current_user after redirect.

If you are building a single-page application, try not to use redirect. Let Javascript handle page switching.

trivialcase

trivialcase OP

Thanks, that was part of the problem. I was also right that I needed to use Guardian to sign in after verifying the emailed token-link. I should probably put together a little article detailing the process of setting up passwordless authentication using the Guardian library since everything I’ve seen so far uses Phoenix.Token, which doesn’t have a very thorough set of functions.

OvermindDL1

OvermindDL1

Guardian is useful if you need JWT. If you are just using it as a token you really should be using Phoenix.Token. And the reason Phoenix does not include little pipeline helpers for it is that they are so simple to write that most just write them straight in their router to call in their pipeline.

If however you want a set of pre-made ones I know there are a couple up on hex.pm. :slight_smile:

trivialcase

trivialcase OP

Thanks! I’m super new to this so I only barely know what I’m doing, just sort of having fun learning. Is there somewhere to learn how to do that? I also have an API that is in Guardian, which is why I used it here too, maybe I should drop it altogether?

OvermindDL1

OvermindDL1

Ehh, depends. If it is already in production, no, no point breaking existing things. If it is not but you are using some of the JWT specific features or plan to, then keep guardian, and use it everywhere to keep things ‘uniform’. If you just need a token everywhere with no special JWT stuff then use phoenix tokens everywhere. :slight_smile:

Lots of docs all over google (this is not really phoenix specific) but I do not have any ready on hand. ^.^;

trivialcase

trivialcase OP

Lol yea it’ll be a while before I’m worrying about production. This is the first time I’m learning how to make apps in any language, I just chose Elixir/Phoenix because it sounded fun (and I have a math background, there is something that feels math here…). I’ve noticed that if you don’t already have a background in Rails or Node, etc, that learning materials can be a little tough to come by. But it’s all good, fun all the same.

OvermindDL1

OvermindDL1

I came from the erlang world instead of the rails/node world, the concepts clicked, but wow it has a weird structure to me, it still does. ^.^

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews