Skip to content

Commit c556e7c

Browse files
authored
Merge pull request #72 from dwyl/cookie-doc
[PR] Adding cookie limit size clarification
2 parents 96abc9e + 554c0dd commit c556e7c

File tree

4 files changed

+77
-30
lines changed

4 files changed

+77
-30
lines changed

README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,13 +284,33 @@ defmodule AppWeb.MicrosoftAuthController do
284284
{:ok, token} = ElixirAuthMicrosoft.get_token(code, conn)
285285
{:ok, profile} = ElixirAuthMicrosoft.get_user_profile(token.access_token)
286286

287+
# Store only essential user info to avoid cookie overflow
288+
# Azure AD tokens can be 8KB+ for users with many group memberships.
289+
# Alternatively, you can store the entire token.
290+
# |> put_session(:token, token)
287291
conn
288-
|> put_view(AppWeb.PageView)
289-
|> render(:welcome, profile: profile)
292+
|> put_session(:user_id, profile.id)
293+
|> put_session(:user_email, profile.mail || profile.userPrincipalName)
294+
|> put_session(:user_name, profile.displayName)
295+
|> redirect(to: "/welcome")
290296
end
291-
end
292297
```
293298

299+
> [!WARNING]
300+
>
301+
> We store only the user's ID, email, and name instead of the entire token object.
302+
> This prevents `Plug.Conn.CookieOverflowError` which occurs when cookies exceed 4096 bytes.
303+
> Microsoft/Azure AD tokens can be very large (8KB+), especially for users who are members
304+
> of many Azure AD groups.
305+
> You can choose to store the entire token, but be aware of potential cookie size issues.
306+
307+
> [!NOTE]
308+
> For production apps where you need to store access tokens for making API calls, consider:
309+
> 1. **Server-side sessions** - Store tokens in a database (PostgreSQL, MySQL) or cache (Redis)
310+
> 2. **Database with session reference** - Store a session ID in the cookie, store the full token in your database
311+
> 3. **Extract only required claims** - Parse the JWT and store only the specific claims you need
312+
313+
294314
The exact controller code implementation is up to you,🎉
295315
but we have provided a working example.
296316

demo/README.md

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -313,16 +313,20 @@ and add the following function.
313313
```elixir
314314
def welcome(conn, _params) do
315315

316-
# Check if there's a session token
317-
case conn |> get_session(:token) do
316+
# Check if there's a user_id in the session
317+
case conn |> get_session(:user_id) do
318318

319319
# If not, we redirect the person to the login page
320320
nil ->
321321
conn |> redirect(to: "/")
322322

323-
# If there's a token, we render the welcome page
324-
token ->
325-
{:ok, profile} = ElixirAuthMicrosoft.get_user_profile(token.access_token)
323+
# If there's a user_id, we render the welcome page with stored user info
324+
user_id ->
325+
profile = %{
326+
id: user_id,
327+
displayName: get_session(conn, :user_name),
328+
userPrincipalName: get_session(conn, :user_email)
329+
}
326330

327331
conn
328332
|> put_view(AppWeb.PageView)
@@ -333,12 +337,12 @@ and add the following function.
333337

334338
We are using the
335339
[`get_session`](https://hexdocs.pm/plug/Plug.Conn.html#get_session/2)
336-
to retrieve the `token` from the session.
340+
to retrieve the user information from the session.
337341
We've *yet* to place it there in the first place,
338342
but don't worry, we'll do it next!
339-
If no `token` is found,
343+
If no `user_id` is found,
340344
we redirect the person to the homepage to login.
341-
If it is, we render the page normally!
345+
If it is, we construct a profile map from the stored session data and render the page normally!
342346

343347
Now let's put the `token` in the session
344348
after the person logs in successfully.
@@ -355,25 +359,38 @@ change the `index` function to the following:
355359
end
356360

357361
{:ok, token} = ElixirAuthMicrosoft.get_token(code, conn)
362+
{:ok, profile} = ElixirAuthMicrosoft.get_user_profile(token.access_token)
358363

359-
364+
# Store only essential user info to avoid cookie overflow
365+
# Azure AD tokens can be 8KB+ for users with many group memberships.
366+
# Alternatively, you can store the entire token.
367+
# |> put_session(:token, token)
360368
conn
361-
|> put_session(:token, token)
369+
|> put_session(:user_id, profile.id)
370+
|> put_session(:user_email, profile.mail || profile.userPrincipalName)
371+
|> put_session(:user_name, profile.displayName)
362372
|> redirect(to: "/welcome")
363373
end
364374
```
365375

366-
We are simply using the
376+
We are using the
367377
[`put_session`](https://hexdocs.pm/plug/Plug.Conn.html#put_session/3)
368-
function to persist the token within the connection session
369-
to later be retrieved by the page
370-
after successful login.
378+
function to persist only the essential user information in the session.
379+
380+
> [!WARNING]
381+
>
382+
> We store only the user's ID, email, and name instead of the entire token object.
383+
> This prevents `Plug.Conn.CookieOverflowError` which occurs when cookies exceed 4096 bytes.
384+
> Microsoft/Azure AD tokens can be very large (8KB+), especially for users who are members
385+
> of many Azure AD groups.
386+
> You can choose to store the entire token, but be aware of potential cookie size issues.
387+
371388
The person is redirected to the `/welcome` page
372389
we've defined earlier if they manage to login.
373390

374391
And that's it!
375392
If you refresh the `/welcome` page,
376-
the token won't be lost! 🎉
393+
the user info won't be lost! 🎉
377394

378395
## 7. Logging out
379396

@@ -443,16 +460,18 @@ Open the file and add the following function:
443460
```elixir
444461
def logout(conn, _params) do
445462

446-
# Clears token from user session
463+
# Clears all user data from session
447464
conn
448-
|> delete_session(:token)
465+
|> clear_session()
449466
|> redirect(to: "/")
450467
end
451468
```
452469

453-
We are simply clearing the person's session
470+
We are simply clearing the person's entire session
454471
and redirecting them to the homepage
455472
(so they can log in again, if they wish to).
473+
Using `clear_session()` ensures all session data is removed,
474+
not just specific keys.
456475

457476

458477
### 7.2 Adding a button so the person logs out

demo/lib/app_web/controllers/microsoft_auth_controller.ex

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@ defmodule AppWeb.MicrosoftAuthController do
1212
end
1313

1414
{:ok, token} = ElixirAuthMicrosoft.get_token(code, conn)
15+
{:ok, profile} = ElixirAuthMicrosoft.get_user_profile(token.access_token)
1516

17+
# Store only essential user info to avoid cookie overflow
18+
# Azure AD tokens can be 8KB+ for users with many group memberships
1619
conn
17-
|> put_session(:token, token)
20+
|> put_session(:user_id, profile.id)
21+
|> put_session(:user_email, profile.mail || profile.userPrincipalName)
22+
|> put_session(:user_name, profile.displayName)
1823
|> redirect(to: "/welcome")
1924
end
2025

@@ -23,10 +28,9 @@ defmodule AppWeb.MicrosoftAuthController do
2328
"""
2429
def logout(conn, _params) do
2530

26-
# Clears token from user session
27-
conn = conn |> delete_session(:token)
28-
31+
# Clears all user data from session
2932
conn
33+
|> clear_session()
3034
|> redirect(to: "/")
3135
end
3236
end

demo/lib/app_web/controllers/page_controller.ex

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@ defmodule AppWeb.PageController do
1010

1111
def welcome(conn, _params) do
1212

13-
# Check if there's a session token
14-
case conn |> get_session(:token) do
13+
# Check if there's a user_id in the session
14+
case conn |> get_session(:user_id) do
1515

1616
# If not, we redirect the user to the login page
1717
nil ->
1818
conn |> redirect(to: "/")
1919

20-
# If there's a token, we render the welcome page
21-
token ->
22-
{:ok, profile} = ElixirAuthMicrosoft.get_user_profile(token.access_token)
20+
# If there's a user_id, we render the welcome page with stored user info
21+
user_id ->
22+
profile = %{
23+
id: user_id,
24+
displayName: get_session(conn, :user_name),
25+
userPrincipalName: get_session(conn, :user_email)
26+
}
2327

2428
conn
2529
|> put_view(AppWeb.PageView)

0 commit comments

Comments
 (0)