We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Post 87
LiveView 02 - Authentication and Routes
Published on: 2025-11-18
Tags:
elixir, Blog, Side Project, LiveView, Phoenix, Framework
Part I - Code Generation
Chapter 2 - Phoenix and Authentication (33)
Now we want to use generators to take care of the Authentication part of our app. Although its not needed in a LiveView it will allow as to do certain things:
Manage Users
Authenticate Requests
Manage Sessions
With this we will want to attach a user to the work that they are doing. We will also want to be sure that a user is signed-in in-order to see survey they want etc. Let's also start to think about endpoints and router to start to trace the paths and functions our user and app will use.
Next we can take care of the generators and deal with, new features link magic link and more.
With all this in mind try to pay as close of attention to the way that we deal with all these features and the way the are all structured.
CRC: Constructors Reducers and Converters
Plug Framework will be the Phoenix version of this idea. We take a data structure and use focused functions to change and reduce the format/structure to work with what we need.
While building and using these ideas try to keep everything named to the right CRC idea. Are we Constructing a new data? Are we Reducing Data into more manageable pieces? Are we Converting from one data type to an other?
Here is a module that will do all the above in one.
iex(1)> defmodule Number do
...(1)> def new(string), do: Integer.parse(string) |> elem(0)
...(1)> def add(number, addend), do: number + addend
...(1)> def to_string(number), do: Integer.to_string(number)
...(1)> end
Notice how this works with integers. It Constructs a new data type. Reduces the data when it appends, then Converts it back to a string. We can then use the new module like this. Remember that & is an anonymous function and it is say to use the function and take the &th and the &th arguments.
iex(2)> list = [1, 2, 3]
[1, 2, 3]
iex(3)> total = Number.new("0")
0
iex(4)> reducer = &Number.add(&2, &1)
#Function<13.126501267/2 in :erl_eval.expr/5>
iex(5)> converter = &Number.to_string/1
&Number.to_string/1
iex(6)> Enum.reduce(list, total, reducer) |> converter.()
"6"
Here is an other way to do the same thing with \ in the iex session.
iex(7)> [first, second, third] = list
[1, 2, 3]
iex(16)> "0" \
iex(16)> |> Number.new \
...(16)> |> Number.add(first) \
...(16)> |> Number.add(second) \
...(16)> |> Number.add(third) \
...(16)> |> Number.to_string
"6"
CRC in Phoenix
So using this idea Phoenix will take a request and send it through a series of pipes and functions that will deal with each part of the request. Here is a small part of the request.
connection
|> process_part_of_request(...)
|> process_part_of_request(...)
|> render()
Let's look at a way that we could do a small request with some built-in elixir functions. This isn't building a request but show how you might build a response. Pay attention to the idea that we build a reducer to add in elements of the request so that we have a full message to send back.
iex(4)> connection = %{request_path: "http://mysite.com/"}
%{request_path: "http://mysite.com/"}
iex(5)> reducer = fn acc, key, value -> Map.put(acc, key, value) end
#Function<19.126501267/3 in :erl_eval.expr/5>
iex(6)> connection |> reducer.(:status, 200) |> reducer.(:body, :ok)
%{body: :ok, request_path: "http://mysite.com/", status: 200}
The Plug.Conn Common Data Structure
The Plug framework is there to change a connection one small bit at a time. Let's open up a iex session withing the LiveView project we built.
iex> %Plug.Conn{}
%Plug.Conn{
...
host: "www.example.com",
method: "GET",
...
resp_body: nil,
resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}],
status: nil
...
}
Reducers in Plug
Now that you have seen the structure of a Plug.Conn you can see what we are working with and that Plugs are basically just reducers. Here are some key features.
• Plugs are essentially reducer functions
• They take a Plug.Conn struct as the first argument
• They return a Plug.Conn struct.
• They can be halted.
With this out in the open you can start to look into Phoenix Configuration code and you might see something like this.
plug Plug.MethodOverride
plug Plug.Head
plug Plug.Session, @session_options
plug PentoWeb.Router
you should mentally translate that code to this:
connection
|> Plug.MethodOverride.call()
|> Plug.Head.call()
|> Plug.Session.call(@session_options)
|> PentoWeb.Router.call()
Phoenix is One Giant function
You should now have a good idea that all you are doing with most of the Phoenix infrastructure is using Plugs to change small things to deal with any request coming from a user. The main sections of the pipeline are: endpoint, router, application.
connection_from_request
|> endpoint
|> router
|> custom_application
The Phoenix Endpoint
If Phoenix is a long chain of reducers the the Endpoint is the constructor at the very beginning of that chain. The endpoint is a simple Elixir module in a file called endpoint.ex. Within that file you will see a bunch of plugs that will deal with the socket for your communication. Head to pento/lib/pento_web/endpoint.ex and look for this line
plug PentoWeb.Router
The Phoenix Router
This is your switch board operator for your page. The router does it's job in three parts:
• First, the router specifies chains of common functions to implement policy.
• Next, the router groups together common requests and ties each one to the correct policy.
• Finally, the router maps individual requests onto the modules that do the hard work of building appropriate responses to individual requests.
Said another way, the endpoint prepares Plug.Conn. The router applies collective policies and then sends each request to the appropriate custom application module based on application policy. Then, custom application modules service a request.
Pipelines are Polices
The first plug takes in a connection and the last one returns a connection. In the mean time we are filling out the %Plug.Conn{} struct with the needed information. Head to lib/pento/pento_web/router.ex and check out the first lines.
pipeline :browser do
plug(:accepts, ["html"])
plug(:fetch_session)
plug(:fetch_live_flash)
plug(:put_root_layout, html: {PentoWeb.Layouts, :root})
plug(:protect_from_forgery)
plug(:put_secure_browser_headers)
end
Or these lines
pipeline :api do
plug(:accepts, ["json"])
end
See what the request will take and what it does to it.
Scopes
These are blocks that help us deal with requests and what we do with them. Still in the same file check this out.
scope "/", PentoWeb do
pipe_through(:browser)
get("/", PageController, :home)
live("/guess", WrongLive)
end
This will take all requests that start from the main page "/". It will pipe through the browser so it will use all the plugs from the pipeline browser. Lastly notice the PentoWeb it will prepend that to each module that we build in the scope.
Routes
Still in the same file let's look at this line.
live("/guess", WrongLive)
Every route starts with a route type, a URL pattern, a module, and (optionally) some options.
Most of that is straightforward, but let’s talk about the module and the route type for a moment.
The module is the code that takes over once this route is hit. For a LiveView route, that module is LiveView and it owns the socket, state, and events for the page.
The route type (live, get, post, etc.) tells Phoenix how to handle the request. A live route runs through the LiveView lifecycle. A normal get or post route goes through a controller action instead, and each HTTP method is handled as a separate function like index/2, create/2, and so on.
Plugs and Authentication
Who is logged in? We will need to build our authentication layer. There will be an infrastructure layer (Left) and the Phoenix and router layer (Right). The left will hold the Tokens and deal with all the login and logout parts. You will need a way to store a user so that will also involve a DB of some kind.
The Right will send the requests and control access to the routes that a user will be able to see.
Generate The Authentication Layer
We will use some built-in generators for this process as the work to build this is not in this book and you should rely on tested and proven code to build things unless you want to spend real time learning each step.
Run the Generator
Running mix phx.gen without arguemnts will allows us to see most all the generators that are available.
[pento] (beta_1_intro *=) ➔ mix phx.gen
mix phx.gen.auth # Generates authentication logic for a resource
...
mix phx.gen.context # Generates a context with functions around an Ecto \
schema
mix phx.gen.embedded # Generates an embedded Ecto schema
mix phx.gen.html # Generates context and controller for an HTML resource
mix phx.gen.json # Generates context and controller for a JSON resource
mix phx.gen.live # Generates LiveView, templates, and context...
...
mix phx.gen.schema # Generates an Ecto schema and migration file
If we were to run the mix phx.auth.gen with arguments we would get an error let's try that real quick to see what kind of error it is.
[pento] ➔ mix phx.gen.auth
** (Mix) Invalid arguments
mix phx.gen.auth expects a context module name, followed by
the schema module and its plural name (used as the schema
table name).
For example:
mix phx.gen.auth Accounts User users
The context serves as the API boundary ...
Okay so we need arguments and the default seems fine let's run that.
mix phx.gen.auth Accounts User users