Pistrie
I’m following a guide on Guardian authentication with elixir, but the need for refresh tokens isn’t very clear to me. This is my current understanding:
- Access tokens allow a user to make secure calls to the API
- Access tokens are powerful, so they need to expire in a timely manner (15 minutes) in order to prevent malicious actors from stealing the token and using it
- In order to prevent the user from having to log in again to get a new access token we use a refresh token (which last longer, 7 days in my case) to regenerate the access token.
Why bother with refresh tokens if they can regenerate access tokens? It seems like misleading security. It’s just an extra step for the attacker. Instead of using the access token directly, he uses the stolen refresh token to generate a new access token.
Here is my session_controller in case it helps:
defmodule AuthTutorialPhoenixWeb.SessionController do
use AuthTutorialPhoenixWeb, :controller
alias AuthTutorialPhoenix.Accounts
alias AuthTutorialPhoenix.Guardian
action_fallback AuthTutorialPhoenixWeb.FallbackController
def new(conn, %{"email" => email, "password" => password}) do
case Accounts.authenticate_user(email, password) do
{:ok, user} ->
{:ok, access_token, _claims} =
Guardian.encode_and_sign(user, %{}, token_type: "access", ttl: {15, :minute})
{:ok, refresh_token, _claims} =
Guardian.encode_and_sign(user, %{}, token_type: "refresh", ttl: {7, :day})
conn
# refresh token is stored as a cookie
|> put_resp_cookie("ruid", refresh_token)
|> put_status(:created)
# access token is an artifact that clients can use to make secure calls to an API server
|> render("token.json", access_token: access_token)
{:error, :unauthorized} ->
body = Jason.encode!(%{error: "unauthorized"})
conn
|> send_resp(401, body)
end
end
def refresh(conn, _params) do
refresh_token =
Plug.Conn.fetch_cookies(conn)
|> Map.from_struct()
|> get_in([:cookies, "ruid"])
# refresh token is used to generate a new access token without needing the user to log in again
case Guardian.exchange(refresh_token, "refresh", "access") do
{:ok, _old_stuff, {new_access_token, _new_claims}} ->
conn
|> put_status(:created)
|> render("token.json", %{
access_token: new_access_token
})
{:error, _reason} ->
body = Jason.encode!(%{error: "unauthorized"})
conn
|> send_resp(401, body)
end
end
def delete(conn, _params) do
conn
|> delete_resp_cookie("ruid")
|> put_status(200)
|> text("Log out successful")
end
end
After some online searching, it seems that you should also need to provide some identification when using a refresh token. Am I doing that here, or is my implementation faulty?
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app?
Looking for hints regarding:
Addi...
New
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
Hi all, I wanted to ask how the community is dealing with post-release steps.
Today we have Ecto migrations, which make sure that the db...
New
Hello,
I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
hauleth
Yes, indeed. That is why using stateless tokens for sessions is dumb idea. You should not use JWTs for sessions and in general you should not use JWTs at all.
LostKobrakai
That assumes a token and a refresh token go through the same level of scrutiny, which might or might not be true. E.g. the access token might grant access statelessly (nothing on the server is checked besides the token itself), while a refresh token might look into the db for changes/invalidations/blocks/….
The access token might be used against a whole fleet of app servers, but the refresh endpoint goes back to the authentication server.
trisolaran
Also worth pointing out that, while refresh tokens can generate access tokens at will, they’re only issued in the beginning when the user authenticates. That gives an attacker a much shorter time window to steal the refresh token.
hauleth
You still need to store it somewhere. In most cases it is stored in Local Storage, which is just one XSS away from being stolen.
trisolaran
You need to store any token you want to use. And with XSS all bets are off anyway aren’t they?
It’s still true that if your attacker is trying to steal your token the time window to do so for refresh tokens is reduced (assuming the attacker is not inside your browser already).
hauleth
You can store session in the HTTP-only cookie which is then it is not readable from the JS, which mean that it cannot be stolen by the mere XSS.
trisolaran
I agree, and this is raising the bar for attackers. But so is using refresh tokens and that’s all I was trying to say
hauleth
Using refresh tokens make the attack more prevalent and harder to detect if anything. Additionally approach of token + refresh token makes everything more convoluted at the same time making you less secure. Ignoring even the fact that if you want to have any authorisation, then you will need to hit DB anyway in each request that does anything sensible. So in short you made your system:
And you have gained absolutely nothing in the process.
dimitarvp
I haven’t been keeping up with security, to the detriment of part of my career prospects I suspect.
What’s a good way to secure API access these days? (I guess the same question can be asked for e.g. keeping game sessions alive as well.)
trisolaran
Not with JWT apparently