8146 lines
247 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Build Power. Not Rent It. Own your digital infrastructure.">
<meta name="author" content="Bunker Operations">
<link rel="canonical" href="https://bnkserve.org/v2/troubleshooting/auth-issues/">
<link rel="prev" href="../common-errors/">
<link rel="next" href="../database-issues/">
<link rel="icon" href="../../../assets/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.1">
<title>Auth Issues - Changemaker Lite</title>
<link rel="stylesheet" href="../../../assets/stylesheets/main.484c7ddc.min.css">
<link rel="stylesheet" href="../../../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="../../../stylesheets/extra.css">
<link rel="stylesheet" href="../../../stylesheets/home.css">
<link rel="stylesheet" href="../../../assets/css/video-player.css">
<script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
<meta property="og:type" content="website" />
<meta property="og:title" content="Auth Issues - Changemaker Lite" />
<meta property="og:description" content="Build Power. Not Rent It. Own your digital infrastructure." />
<meta property="og:image" content="https://bnkserve.org/assets/images/social/v2/troubleshooting/auth-issues.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://bnkserve.org/v2/troubleshooting/auth-issues/" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:title" content="Auth Issues - Changemaker Lite" />
<meta property="twitter:description" content="Build Power. Not Rent It. Own your digital infrastructure." />
<meta property="twitter:image" content="https://bnkserve.org/assets/images/social/v2/troubleshooting/auth-issues.png" />
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="amber">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#authentication-and-authorization-issues" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow md-header--lifted" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../../.." title="Changemaker Lite" class="md-header__button md-logo" aria-label="Changemaker Lite" data-md-component="logo">
<img src="../../../assets/logo.png" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Changemaker Lite
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Auth Issues
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="amber" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31"/></svg>
</label>
<input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="deep-purple" data-md-color-accent="amber" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://gitea.bnkops.com/admin/changemaker.lite" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
changemaker.lite
</div>
</a>
</div>
</nav>
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="../../" class="md-tabs__link">
V2 Documentation
</a>
</li>
<li class="md-tabs__item">
<a href="../../../phil/" class="md-tabs__link">
Philosophy
</a>
</li>
<li class="md-tabs__item">
<a href="../../../v1/" class="md-tabs__link">
V1 Documentation (Legacy)
</a>
</li>
<li class="md-tabs__item">
<a href="../../../blog/" class="md-tabs__link">
Blog
</a>
</li>
</ul>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../../.." title="Changemaker Lite" class="md-nav__button md-logo" aria-label="Changemaker Lite" data-md-component="logo">
<img src="../../../assets/logo.png" alt="logo">
</a>
Changemaker Lite
</label>
<div class="md-nav__source">
<a href="https://gitea.bnkops.com/admin/changemaker.lite" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
changemaker.lite
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
<div class="md-nav__link md-nav__container">
<a href="../../" class="md-nav__link ">
<span class="md-ellipsis">
V2 Documentation
</span>
</a>
<label class="md-nav__link " for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
V2 Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_2" >
<div class="md-nav__link md-nav__container">
<a href="../../getting-started/" class="md-nav__link ">
<span class="md-ellipsis">
Getting Started
</span>
</a>
<label class="md-nav__link " for="__nav_2_2" id="__nav_2_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../getting-started/quick-start/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_3" >
<div class="md-nav__link md-nav__container">
<a href="../../architecture/" class="md-nav__link ">
<span class="md-ellipsis">
Architecture
</span>
</a>
<label class="md-nav__link " for="__nav_2_3" id="__nav_2_3_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_3">
<span class="md-nav__icon md-icon"></span>
Architecture
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../architecture/dual-api/" class="md-nav__link">
<span class="md-ellipsis">
Dual API System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../architecture/authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication & Security
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_4" >
<div class="md-nav__link md-nav__container">
<a href="../../backend/" class="md-nav__link ">
<span class="md-ellipsis">
Backend
</span>
</a>
<label class="md-nav__link " for="__nav_2_4" id="__nav_2_4_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_4">
<span class="md-nav__icon md-icon"></span>
Backend
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/modules/" class="md-nav__link">
<span class="md-ellipsis">
Modules
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/services/" class="md-nav__link">
<span class="md-ellipsis">
Services
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/middleware/" class="md-nav__link">
<span class="md-ellipsis">
Middleware
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../backend/utilities/" class="md-nav__link">
<span class="md-ellipsis">
Utilities
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_5" >
<div class="md-nav__link md-nav__container">
<a href="../../frontend/" class="md-nav__link ">
<span class="md-ellipsis">
Frontend
</span>
</a>
<label class="md-nav__link " for="__nav_2_5" id="__nav_2_5_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_5">
<span class="md-nav__icon md-icon"></span>
Frontend
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../frontend/components/" class="md-nav__link">
<span class="md-ellipsis">
Components
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../frontend/layouts/" class="md-nav__link">
<span class="md-ellipsis">
Layouts
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../frontend/pages/" class="md-nav__link">
<span class="md-ellipsis">
Pages
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_6" >
<div class="md-nav__link md-nav__container">
<a href="../../database/" class="md-nav__link ">
<span class="md-ellipsis">
Database
</span>
</a>
<label class="md-nav__link " for="__nav_2_6" id="__nav_2_6_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_6">
<span class="md-nav__icon md-icon"></span>
Database
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../database/schema/" class="md-nav__link">
<span class="md-ellipsis">
Schema Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../database/migrations/" class="md-nav__link">
<span class="md-ellipsis">
Migrations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../database/seeding/" class="md-nav__link">
<span class="md-ellipsis">
Seeding
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../database/indexes/" class="md-nav__link">
<span class="md-ellipsis">
Indexes
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../database/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_7" >
<div class="md-nav__link md-nav__container">
<a href="../../features/" class="md-nav__link ">
<span class="md-ellipsis">
Features
</span>
</a>
<label class="md-nav__link " for="__nav_2_7" id="__nav_2_7_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_7">
<span class="md-nav__icon md-icon"></span>
Features
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/influence/" class="md-nav__link">
<span class="md-ellipsis">
Influence
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/map/" class="md-nav__link">
<span class="md-ellipsis">
Map
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/landing-pages/" class="md-nav__link">
<span class="md-ellipsis">
Landing Pages
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/email-templates/" class="md-nav__link">
<span class="md-ellipsis">
Email Templates
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/media/" class="md-nav__link">
<span class="md-ellipsis">
Media
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/newsletter/" class="md-nav__link">
<span class="md-ellipsis">
Newsletter
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/observability/" class="md-nav__link">
<span class="md-ellipsis">
Observability
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../features/tunnel/" class="md-nav__link">
<span class="md-ellipsis">
Tunnel
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_8" >
<div class="md-nav__link md-nav__container">
<a href="../../deployment/" class="md-nav__link ">
<span class="md-ellipsis">
Deployment
</span>
</a>
<label class="md-nav__link " for="__nav_2_8" id="__nav_2_8_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_8">
<span class="md-nav__icon md-icon"></span>
Deployment
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../deployment/docker-compose/" class="md-nav__link">
<span class="md-ellipsis">
Docker Compose
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/environment-variables/" class="md-nav__link">
<span class="md-ellipsis">
Environment Variables
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/nginx/" class="md-nav__link">
<span class="md-ellipsis">
Nginx Configuration
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/ssl-tls/" class="md-nav__link">
<span class="md-ellipsis">
SSL/TLS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/tunneling/" class="md-nav__link">
<span class="md-ellipsis">
Tunneling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/monitoring-stack/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Stack
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/healthchecks/" class="md-nav__link">
<span class="md-ellipsis">
Health Checks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/scaling/" class="md-nav__link">
<span class="md-ellipsis">
Scaling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../deployment/backup-restore/" class="md-nav__link">
<span class="md-ellipsis">
Backup & Restore
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_9" >
<div class="md-nav__link md-nav__container">
<a href="../../development/" class="md-nav__link ">
<span class="md-ellipsis">
Development
</span>
</a>
<label class="md-nav__link " for="__nav_2_9" id="__nav_2_9_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_9">
<span class="md-nav__icon md-icon"></span>
Development
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../development/local-setup/" class="md-nav__link">
<span class="md-ellipsis">
Local Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/docker-workflow/" class="md-nav__link">
<span class="md-ellipsis">
Docker Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/git-workflow/" class="md-nav__link">
<span class="md-ellipsis">
Git Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/npm-commands/" class="md-nav__link">
<span class="md-ellipsis">
NPM Commands
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/migrations/" class="md-nav__link">
<span class="md-ellipsis">
Migrations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/typescript/" class="md-nav__link">
<span class="md-ellipsis">
TypeScript
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/debugging/" class="md-nav__link">
<span class="md-ellipsis">
Debugging
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../development/code-style/" class="md-nav__link">
<span class="md-ellipsis">
Code Style
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_10" >
<div class="md-nav__link md-nav__container">
<a href="../../api-reference/" class="md-nav__link ">
<span class="md-ellipsis">
API Reference
</span>
</a>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_10">
<span class="md-nav__icon md-icon"></span>
API Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_11" >
<div class="md-nav__link md-nav__container">
<a href="../../user-guides/" class="md-nav__link ">
<span class="md-ellipsis">
User Guides
</span>
</a>
<label class="md-nav__link " for="__nav_2_11" id="__nav_2_11_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_11_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_11">
<span class="md-nav__icon md-icon"></span>
User Guides
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../user-guides/admin-guide/" class="md-nav__link">
<span class="md-ellipsis">
Admin Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/campaign-manager-guide/" class="md-nav__link">
<span class="md-ellipsis">
Campaign Manager Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/map-organizer-guide/" class="md-nav__link">
<span class="md-ellipsis">
Map Organizer Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/content-editor-guide/" class="md-nav__link">
<span class="md-ellipsis">
Content Editor Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../user-guides/volunteer-guide/" class="md-nav__link">
<span class="md-ellipsis">
Volunteer Guide
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_12" checked>
<div class="md-nav__link md-nav__container">
<a href="../" class="md-nav__link ">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
<label class="md-nav__link " for="__nav_2_12" id="__nav_2_12_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_12_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2_12">
<span class="md-nav__icon md-icon"></span>
Troubleshooting
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../faq/" class="md-nav__link">
<span class="md-ellipsis">
FAQ
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../common-errors/" class="md-nav__link">
<span class="md-ellipsis">
Common Errors
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Auth Issues
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Auth Issues
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#overview" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
<nav class="md-nav" aria-label="Overview">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#authentication-system" class="md-nav__link">
<span class="md-ellipsis">
Authentication System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#authorization-system" class="md-nav__link">
<span class="md-ellipsis">
Authorization System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#security-features" class="md-nav__link">
<span class="md-ellipsis">
Security Features
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#login-failures" class="md-nav__link">
<span class="md-ellipsis">
Login Failures
</span>
</a>
<nav class="md-nav" aria-label="Login Failures">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#invalid-credentials" class="md-nav__link">
<span class="md-ellipsis">
Invalid Credentials
</span>
</a>
<nav class="md-nav" aria-label="Invalid Credentials">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#account-suspended" class="md-nav__link">
<span class="md-ellipsis">
Account Suspended
</span>
</a>
<nav class="md-nav" aria-label="Account Suspended">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_1" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_1" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_1" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_1" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#email-not-verified" class="md-nav__link">
<span class="md-ellipsis">
Email Not Verified
</span>
</a>
<nav class="md-nav" aria-label="Email Not Verified">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_2" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_2" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_2" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_2" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#token-issues" class="md-nav__link">
<span class="md-ellipsis">
Token Issues
</span>
</a>
<nav class="md-nav" aria-label="Token Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#token-expired" class="md-nav__link">
<span class="md-ellipsis">
Token Expired
</span>
</a>
<nav class="md-nav" aria-label="Token Expired">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_3" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_3" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_3" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_3" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#invalid-token" class="md-nav__link">
<span class="md-ellipsis">
Invalid Token
</span>
</a>
<nav class="md-nav" aria-label="Invalid Token">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_4" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_4" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_4" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_4" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#token-not-found-in-header" class="md-nav__link">
<span class="md-ellipsis">
Token Not Found in Header
</span>
</a>
<nav class="md-nav" aria-label="Token Not Found in Header">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_5" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_5" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_5" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_5" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#refresh-token-invalid" class="md-nav__link">
<span class="md-ellipsis">
Refresh Token Invalid
</span>
</a>
<nav class="md-nav" aria-label="Refresh Token Invalid">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_6" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_6" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_6" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_6" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#permission-errors" class="md-nav__link">
<span class="md-ellipsis">
Permission Errors
</span>
</a>
<nav class="md-nav" aria-label="Permission Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#insufficient-permissions" class="md-nav__link">
<span class="md-ellipsis">
Insufficient Permissions
</span>
</a>
<nav class="md-nav" aria-label="Insufficient Permissions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_7" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_7" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_7" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_7" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#role-restrictions" class="md-nav__link">
<span class="md-ellipsis">
Role Restrictions
</span>
</a>
<nav class="md-nav" aria-label="Role Restrictions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_8" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_8" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_8" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_8" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#session-issues" class="md-nav__link">
<span class="md-ellipsis">
Session Issues
</span>
</a>
<nav class="md-nav" aria-label="Session Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#session-timeout" class="md-nav__link">
<span class="md-ellipsis">
Session Timeout
</span>
</a>
<nav class="md-nav" aria-label="Session Timeout">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_9" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#current-behavior" class="md-nav__link">
<span class="md-ellipsis">
Current Behavior
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_9" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_9" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#multiple-device-conflicts" class="md-nav__link">
<span class="md-ellipsis">
Multiple Device Conflicts
</span>
</a>
<nav class="md-nav" aria-label="Multiple Device Conflicts">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_10" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#current-behavior_1" class="md-nav__link">
<span class="md-ellipsis">
Current Behavior
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_10" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_10" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#password-reset-issues" class="md-nav__link">
<span class="md-ellipsis">
Password Reset Issues
</span>
</a>
<nav class="md-nav" aria-label="Password Reset Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#reset-link-expired" class="md-nav__link">
<span class="md-ellipsis">
Reset Link Expired
</span>
</a>
<nav class="md-nav" aria-label="Reset Link Expired">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_11" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_9" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_11" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_11" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#email-not-received" class="md-nav__link">
<span class="md-ellipsis">
Email Not Received
</span>
</a>
<nav class="md-nav" aria-label="Email Not Received">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_12" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_10" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_12" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_12" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#rate-limiting" class="md-nav__link">
<span class="md-ellipsis">
Rate Limiting
</span>
</a>
<nav class="md-nav" aria-label="Rate Limiting">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#too-many-login-attempts" class="md-nav__link">
<span class="md-ellipsis">
Too Many Login Attempts
</span>
</a>
<nav class="md-nav" aria-label="Too Many Login Attempts">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_13" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_11" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_13" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_13" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#account-temporarily-locked" class="md-nav__link">
<span class="md-ellipsis">
Account Temporarily Locked
</span>
</a>
<nav class="md-nav" aria-label="Account Temporarily Locked">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_14" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_14" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_14" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#debugging-auth" class="md-nav__link">
<span class="md-ellipsis">
Debugging Auth
</span>
</a>
<nav class="md-nav" aria-label="Debugging Auth">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#checking-jwt-payload" class="md-nav__link">
<span class="md-ellipsis">
Checking JWT Payload
</span>
</a>
<nav class="md-nav" aria-label="Checking JWT Payload">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#how-to-decode-jwt" class="md-nav__link">
<span class="md-ellipsis">
How to Decode JWT
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#verifying-refresh-tokens" class="md-nav__link">
<span class="md-ellipsis">
Verifying Refresh Tokens
</span>
</a>
<nav class="md-nav" aria-label="Verifying Refresh Tokens">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#check-refresh-token-in-database" class="md-nav__link">
<span class="md-ellipsis">
Check Refresh Token in Database
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#checking-user-status" class="md-nav__link">
<span class="md-ellipsis">
Checking User Status
</span>
</a>
<nav class="md-nav" aria-label="Checking User Status">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#view-user-details" class="md-nav__link">
<span class="md-ellipsis">
View User Details
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#related-documentation" class="md-nav__link">
<span class="md-ellipsis">
Related Documentation
</span>
</a>
<nav class="md-nav" aria-label="Related Documentation">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#authentication-documentation" class="md-nav__link">
<span class="md-ellipsis">
Authentication Documentation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#other-troubleshooting" class="md-nav__link">
<span class="md-ellipsis">
Other Troubleshooting
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#security-resources" class="md-nav__link">
<span class="md-ellipsis">
Security Resources
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../database-issues/" class="md-nav__link">
<span class="md-ellipsis">
Database Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../docker-issues/" class="md-nav__link">
<span class="md-ellipsis">
Docker Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../email-issues/" class="md-nav__link">
<span class="md-ellipsis">
Email Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../geocoding-issues/" class="md-nav__link">
<span class="md-ellipsis">
Geocoding Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../monitoring-issues/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../performance-optimization/" class="md-nav__link">
<span class="md-ellipsis">
Performance Optimization
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_13" >
<div class="md-nav__link md-nav__container">
<a href="../../migration/" class="md-nav__link ">
<span class="md-ellipsis">
Migration
</span>
</a>
<label class="md-nav__link " for="__nav_2_13" id="__nav_2_13_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_13_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_13">
<span class="md-nav__icon md-icon"></span>
Migration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../migration/feature-parity/" class="md-nav__link">
<span class="md-ellipsis">
Feature Parity
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../migration/breaking-changes/" class="md-nav__link">
<span class="md-ellipsis">
Breaking Changes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../migration/api-changes/" class="md-nav__link">
<span class="md-ellipsis">
API Changes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../migration/data-migration/" class="md-nav__link">
<span class="md-ellipsis">
Data Migration
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_14" >
<div class="md-nav__link md-nav__container">
<a href="../../contributing/" class="md-nav__link ">
<span class="md-ellipsis">
Contributing
</span>
</a>
<label class="md-nav__link " for="__nav_2_14" id="__nav_2_14_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_14_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_14">
<span class="md-nav__icon md-icon"></span>
Contributing
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../contributing/development-setup/" class="md-nav__link">
<span class="md-ellipsis">
Development Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../contributing/code-of-conduct/" class="md-nav__link">
<span class="md-ellipsis">
Code of Conduct
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../contributing/pull-requests/" class="md-nav__link">
<span class="md-ellipsis">
Pull Requests
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../contributing/roadmap/" class="md-nav__link">
<span class="md-ellipsis">
Roadmap
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../phil/" class="md-nav__link">
<span class="md-ellipsis">
Philosophy
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../v1/" class="md-nav__link">
<span class="md-ellipsis">
V1 Documentation (Legacy)
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../blog/" class="md-nav__link">
<span class="md-ellipsis">
Blog
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#overview" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
<nav class="md-nav" aria-label="Overview">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#authentication-system" class="md-nav__link">
<span class="md-ellipsis">
Authentication System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#authorization-system" class="md-nav__link">
<span class="md-ellipsis">
Authorization System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#security-features" class="md-nav__link">
<span class="md-ellipsis">
Security Features
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#login-failures" class="md-nav__link">
<span class="md-ellipsis">
Login Failures
</span>
</a>
<nav class="md-nav" aria-label="Login Failures">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#invalid-credentials" class="md-nav__link">
<span class="md-ellipsis">
Invalid Credentials
</span>
</a>
<nav class="md-nav" aria-label="Invalid Credentials">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#account-suspended" class="md-nav__link">
<span class="md-ellipsis">
Account Suspended
</span>
</a>
<nav class="md-nav" aria-label="Account Suspended">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_1" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_1" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_1" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_1" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#email-not-verified" class="md-nav__link">
<span class="md-ellipsis">
Email Not Verified
</span>
</a>
<nav class="md-nav" aria-label="Email Not Verified">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_2" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_2" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_2" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_2" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#token-issues" class="md-nav__link">
<span class="md-ellipsis">
Token Issues
</span>
</a>
<nav class="md-nav" aria-label="Token Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#token-expired" class="md-nav__link">
<span class="md-ellipsis">
Token Expired
</span>
</a>
<nav class="md-nav" aria-label="Token Expired">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_3" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_3" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_3" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_3" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#invalid-token" class="md-nav__link">
<span class="md-ellipsis">
Invalid Token
</span>
</a>
<nav class="md-nav" aria-label="Invalid Token">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_4" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_4" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_4" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_4" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#token-not-found-in-header" class="md-nav__link">
<span class="md-ellipsis">
Token Not Found in Header
</span>
</a>
<nav class="md-nav" aria-label="Token Not Found in Header">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_5" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_5" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_5" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_5" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#refresh-token-invalid" class="md-nav__link">
<span class="md-ellipsis">
Refresh Token Invalid
</span>
</a>
<nav class="md-nav" aria-label="Refresh Token Invalid">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_6" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_6" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_6" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_6" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#permission-errors" class="md-nav__link">
<span class="md-ellipsis">
Permission Errors
</span>
</a>
<nav class="md-nav" aria-label="Permission Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#insufficient-permissions" class="md-nav__link">
<span class="md-ellipsis">
Insufficient Permissions
</span>
</a>
<nav class="md-nav" aria-label="Insufficient Permissions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_7" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_7" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_7" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_7" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#role-restrictions" class="md-nav__link">
<span class="md-ellipsis">
Role Restrictions
</span>
</a>
<nav class="md-nav" aria-label="Role Restrictions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_8" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_8" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_8" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_8" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#session-issues" class="md-nav__link">
<span class="md-ellipsis">
Session Issues
</span>
</a>
<nav class="md-nav" aria-label="Session Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#session-timeout" class="md-nav__link">
<span class="md-ellipsis">
Session Timeout
</span>
</a>
<nav class="md-nav" aria-label="Session Timeout">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_9" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#current-behavior" class="md-nav__link">
<span class="md-ellipsis">
Current Behavior
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_9" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_9" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#multiple-device-conflicts" class="md-nav__link">
<span class="md-ellipsis">
Multiple Device Conflicts
</span>
</a>
<nav class="md-nav" aria-label="Multiple Device Conflicts">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_10" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#current-behavior_1" class="md-nav__link">
<span class="md-ellipsis">
Current Behavior
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_10" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_10" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#password-reset-issues" class="md-nav__link">
<span class="md-ellipsis">
Password Reset Issues
</span>
</a>
<nav class="md-nav" aria-label="Password Reset Issues">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#reset-link-expired" class="md-nav__link">
<span class="md-ellipsis">
Reset Link Expired
</span>
</a>
<nav class="md-nav" aria-label="Reset Link Expired">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_11" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_9" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_11" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_11" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#email-not-received" class="md-nav__link">
<span class="md-ellipsis">
Email Not Received
</span>
</a>
<nav class="md-nav" aria-label="Email Not Received">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_12" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_10" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_12" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_12" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#rate-limiting" class="md-nav__link">
<span class="md-ellipsis">
Rate Limiting
</span>
</a>
<nav class="md-nav" aria-label="Rate Limiting">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#too-many-login-attempts" class="md-nav__link">
<span class="md-ellipsis">
Too Many Login Attempts
</span>
</a>
<nav class="md-nav" aria-label="Too Many Login Attempts">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_13" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-causes_11" class="md-nav__link">
<span class="md-ellipsis">
Common Causes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_13" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_13" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#account-temporarily-locked" class="md-nav__link">
<span class="md-ellipsis">
Account Temporarily Locked
</span>
</a>
<nav class="md-nav" aria-label="Account Temporarily Locked">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#symptoms_14" class="md-nav__link">
<span class="md-ellipsis">
Symptoms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#solutions_14" class="md-nav__link">
<span class="md-ellipsis">
Solutions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prevention_14" class="md-nav__link">
<span class="md-ellipsis">
Prevention
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#debugging-auth" class="md-nav__link">
<span class="md-ellipsis">
Debugging Auth
</span>
</a>
<nav class="md-nav" aria-label="Debugging Auth">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#checking-jwt-payload" class="md-nav__link">
<span class="md-ellipsis">
Checking JWT Payload
</span>
</a>
<nav class="md-nav" aria-label="Checking JWT Payload">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#how-to-decode-jwt" class="md-nav__link">
<span class="md-ellipsis">
How to Decode JWT
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#verifying-refresh-tokens" class="md-nav__link">
<span class="md-ellipsis">
Verifying Refresh Tokens
</span>
</a>
<nav class="md-nav" aria-label="Verifying Refresh Tokens">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#check-refresh-token-in-database" class="md-nav__link">
<span class="md-ellipsis">
Check Refresh Token in Database
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#checking-user-status" class="md-nav__link">
<span class="md-ellipsis">
Checking User Status
</span>
</a>
<nav class="md-nav" aria-label="Checking User Status">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#view-user-details" class="md-nav__link">
<span class="md-ellipsis">
View User Details
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#related-documentation" class="md-nav__link">
<span class="md-ellipsis">
Related Documentation
</span>
</a>
<nav class="md-nav" aria-label="Related Documentation">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#authentication-documentation" class="md-nav__link">
<span class="md-ellipsis">
Authentication Documentation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#other-troubleshooting" class="md-nav__link">
<span class="md-ellipsis">
Other Troubleshooting
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#security-resources" class="md-nav__link">
<span class="md-ellipsis">
Security Resources
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<nav class="md-path" aria-label="Navigation" >
<ol class="md-path__list">
<li class="md-path__item">
<a href="../../.." class="md-path__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-path__item">
<a href="../../" class="md-path__link">
<span class="md-ellipsis">
V2 Documentation
</span>
</a>
</li>
<li class="md-path__item">
<a href="../" class="md-path__link">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
</li>
</ol>
</nav>
<article class="md-content__inner md-typeset">
<a href="https://gitea.bnkops.com/admin/changemaker.lite/src/branch/main/mkdocs/docs/v2/troubleshooting/auth-issues.md" title="Edit this page" class="md-content__button md-icon" rel="edit">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg>
</a>
<a href="https://gitea.bnkops.com/admin/changemaker.lite/src/branch/main/mkdocs/docs/v2/troubleshooting/auth-issues.md" title="View source of this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.2 8.2 0 0 1-1.23-2"/></svg>
</a>
<h1 id="authentication-and-authorization-issues">Authentication and Authorization Issues<a class="headerlink" href="#authentication-and-authorization-issues" title="Permanent link">&para;</a></h1>
<p>This guide covers authentication (who you are) and authorization (what you can do) problems in Changemaker Lite V2.</p>
<h2 id="overview">Overview<a class="headerlink" href="#overview" title="Permanent link">&para;</a></h2>
<h3 id="authentication-system">Authentication System<a class="headerlink" href="#authentication-system" title="Permanent link">&para;</a></h3>
<p>Changemaker Lite V2 uses <strong>JWT-based authentication</strong>:</p>
<ul>
<li><strong>Access tokens</strong> - Short-lived (15 minutes), stored in memory</li>
<li><strong>Refresh tokens</strong> - Long-lived (7 days), stored in database</li>
<li><strong>bcrypt passwords</strong> - Hashed with salt (10 rounds)</li>
<li><strong>Token rotation</strong> - New refresh token on each refresh</li>
</ul>
<h3 id="authorization-system">Authorization System<a class="headerlink" href="#authorization-system" title="Permanent link">&para;</a></h3>
<p><strong>Role-based access control (RBAC)</strong> with 5 roles:</p>
<table>
<thead>
<tr>
<th>Role</th>
<th>Level</th>
<th>Permissions</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>SUPER_ADMIN</code></td>
<td>5</td>
<td>Full access to everything</td>
</tr>
<tr>
<td><code>INFLUENCE_ADMIN</code></td>
<td>4</td>
<td>Manage campaigns, responses, email queue</td>
</tr>
<tr>
<td><code>MAP_ADMIN</code></td>
<td>3</td>
<td>Manage locations, cuts, shifts, canvass</td>
</tr>
<tr>
<td><code>USER</code></td>
<td>2</td>
<td>View public content, canvass (if assigned shift)</td>
</tr>
<tr>
<td><code>TEMP</code></td>
<td>1</td>
<td>Very limited - shift signup confirmation only</td>
</tr>
</tbody>
</table>
<h3 id="security-features">Security Features<a class="headerlink" href="#security-features" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Password policy</strong> - 12+ chars, uppercase, lowercase, digit</li>
<li><strong>User enumeration prevention</strong> - Generic error messages</li>
<li><strong>Rate limiting</strong> - 10 requests/min on auth endpoints</li>
<li><strong>Refresh token rotation</strong> - Atomic transaction prevents race conditions</li>
<li><strong>Redis authentication</strong> - Required password for Redis connection</li>
</ul>
<hr />
<h2 id="login-failures">Login Failures<a class="headerlink" href="#login-failures" title="Permanent link">&para;</a></h2>
<h3 id="invalid-credentials">Invalid Credentials<a class="headerlink" href="#invalid-credentials" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟡 Medium</p>
<h4 id="symptoms">Symptoms<a class="headerlink" href="#symptoms" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="p">{</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Unauthorized&quot;</span><span class="p">,</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Invalid credentials&quot;</span>
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="p">}</span>
</span></code></pre></div>
<p>Same message for:
- User not found
- Wrong password
- User suspended</p>
<p>This is intentional (prevents user enumeration).</p>
<h4 id="common-causes">Common Causes<a class="headerlink" href="#common-causes" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Wrong password</strong> - Password incorrect</li>
<li><strong>User doesn't exist</strong> - Email not registered</li>
<li><strong>Typo in email</strong> - Email address wrong</li>
<li><strong>Account suspended</strong> - User marked as suspended</li>
</ol>
<h4 id="solutions">Solutions<a class="headerlink" href="#solutions" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Verify user exists</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="c1"># Check database</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT email, role FROM \&quot;User\&quot; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a>
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="c1"># If no result, user doesn&#39;t exist</span>
</span></code></pre></div>
<p><strong>Solution 2: Reset password</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="c1"># Generate bcrypt hash for new password</span>
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>api<span class="w"> </span>node<span class="w"> </span>-e<span class="w"> </span><span class="s2">&quot;</span>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="s2">const bcrypt = require(&#39;bcryptjs&#39;);</span>
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="s2">const hash = bcrypt.hashSync(&#39;NewPassword123!&#39;, 10);</span>
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="s2">console.log(hash);</span>
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a><span class="s2">&quot;</span>
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a>
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a><span class="c1"># Update password</span>
</span><span id="__span-2-9"><a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-2-10"><a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE \&quot;User\&quot; SET password = &#39;\$2a\$10\$...&#39; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span></code></pre></div>
<p><strong>Solution 3: Create missing user</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="c1"># Via API</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://localhost:4000/api/auth/register<span class="w"> </span><span class="se">\</span>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="s1"> &quot;email&quot;: &quot;user@example.com&quot;,</span>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="s1"> &quot;password&quot;: &quot;SecurePass123!&quot;,</span>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="s1"> &quot;name&quot;: &quot;User Name&quot;</span>
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="s1"> }&#39;</span>
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a>
</span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="c1"># Or via admin UI at /app/users</span>
</span></code></pre></div>
<p><strong>Solution 4: Check for suspended account</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="c1"># Check user status</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT email, role, \&quot;createdAt\&quot; FROM \&quot;User\&quot; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="c1"># If suspended field exists and is true, unsuspend:</span>
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="c1"># (Note: V2 doesn&#39;t have suspended field yet, but may be added)</span>
</span></code></pre></div>
<p><strong>Solution 5: Check password requirements</strong></p>
<p>Password must meet requirements:
- 12+ characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 digit</p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="c1"># Valid examples:</span>
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a>SecurePass123!
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a>MyP@ssword99
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a>Admin12345678
</span></code></pre></div>
<h4 id="prevention">Prevention<a class="headerlink" href="#prevention" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Password manager</strong> - Use password manager to avoid typos</li>
<li><strong>Password reset flow</strong> - Implement forgot password feature</li>
<li><strong>Clear requirements</strong> - Display password requirements on register</li>
<li><strong>User-friendly errors</strong> - Guide users without revealing if email exists</li>
</ul>
<div class="admonition warning">
<p class="admonition-title">User Enumeration</p>
<p>The same error message for "user not found" and "wrong password" is intentional security behavior to prevent attackers from discovering valid email addresses.</p>
</div>
<hr />
<h3 id="account-suspended">Account Suspended<a class="headerlink" href="#account-suspended" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟠 High</p>
<h4 id="symptoms_1">Symptoms<a class="headerlink" href="#symptoms_1" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="p">{</span>
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Forbidden&quot;</span><span class="p">,</span>
</span><span id="__span-6-3"><a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Account suspended&quot;</span>
</span><span id="__span-6-4"><a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="p">}</span>
</span></code></pre></div>
<p>User can't log in even with correct credentials.</p>
<h4 id="common-causes_1">Common Causes<a class="headerlink" href="#common-causes_1" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Manual suspension</strong> - Admin suspended account</li>
<li><strong>Security violation</strong> - Account flagged for suspicious activity</li>
<li><strong>Terms violation</strong> - Account suspended for policy violation</li>
</ol>
<h4 id="solutions_1">Solutions<a class="headerlink" href="#solutions_1" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Check suspension status</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="c1"># Check if user has suspended flag (if implemented)</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT email, role FROM \&quot;User\&quot; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span></code></pre></div>
<p><strong>Solution 2: Unsuspend account</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="c1"># If suspension field exists:</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE \&quot;User\&quot; SET suspended = false WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a>
</span><span id="__span-8-5"><a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="c1"># Or delete user and recreate</span>
</span></code></pre></div>
<p><strong>Solution 3: Contact administrator</strong></p>
<p>If you're a user:
1. Contact system administrator
2. Provide your email address
3. Wait for account review</p>
<h4 id="prevention_1">Prevention<a class="headerlink" href="#prevention_1" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Suspension policy</strong> - Clear policy on suspension reasons</li>
<li><strong>Appeal process</strong> - Allow users to appeal suspensions</li>
<li><strong>Audit trail</strong> - Log suspension reasons and who suspended</li>
</ul>
<div class="admonition note">
<p class="admonition-title">V2 Status</p>
<p>V2 doesn't currently have a suspended field. This section is for future implementation or if added via custom migration.</p>
</div>
<hr />
<h3 id="email-not-verified">Email Not Verified<a class="headerlink" href="#email-not-verified" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟢 Low</p>
<h4 id="symptoms_2">Symptoms<a class="headerlink" href="#symptoms_2" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="p">{</span>
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Forbidden&quot;</span><span class="p">,</span>
</span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Email not verified. Please check your email for verification link.&quot;</span>
</span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="p">}</span>
</span></code></pre></div>
<h4 id="common-causes_2">Common Causes<a class="headerlink" href="#common-causes_2" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Email not verified</strong> - User didn't click verification link</li>
<li><strong>Verification email not received</strong> - Email went to spam</li>
<li><strong>Verification link expired</strong> - Link older than 24 hours</li>
</ol>
<h4 id="solutions_2">Solutions<a class="headerlink" href="#solutions_2" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Check verification status</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="c1"># Check if emailVerified field exists</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT email, \&quot;createdAt\&quot; FROM \&quot;User\&quot; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span></code></pre></div>
<p><strong>Solution 2: Manually verify email</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="c1"># Mark email as verified</span>
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE \&quot;User\&quot; SET \&quot;emailVerified\&quot; = true WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span></code></pre></div>
<p><strong>Solution 3: Resend verification email</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="c1"># Via API (if endpoint exists)</span>
</span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://localhost:4000/api/auth/resend-verification<span class="w"> </span><span class="se">\</span>
</span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-12-4"><a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;email&quot;: &quot;user@example.com&quot;}&#39;</span>
</span></code></pre></div>
<p><strong>Solution 4: Check spam folder</strong></p>
<p>Verification emails may be marked as spam. Check:
1. Spam/Junk folder
2. Promotions tab (Gmail)
3. Email filters</p>
<h4 id="prevention_2">Prevention<a class="headerlink" href="#prevention_2" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Clear instructions</strong> - Tell users to check spam</li>
<li><strong>From address</strong> - Use recognizable from address</li>
<li><strong>SPF/DKIM/DMARC</strong> - Configure email authentication</li>
<li><strong>Resend option</strong> - Easy way to resend verification</li>
</ul>
<div class="admonition note">
<p class="admonition-title">V2 Status</p>
<p>V2 doesn't currently require email verification for login. This section is for future implementation.</p>
</div>
<hr />
<h2 id="token-issues">Token Issues<a class="headerlink" href="#token-issues" title="Permanent link">&para;</a></h2>
<h3 id="token-expired">Token Expired<a class="headerlink" href="#token-expired" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟡 Medium</p>
<h4 id="symptoms_3">Symptoms<a class="headerlink" href="#symptoms_3" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="p">{</span>
</span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Unauthorized&quot;</span><span class="p">,</span>
</span><span id="__span-13-3"><a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Token expired&quot;</span>
</span><span id="__span-13-4"><a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a><span class="p">}</span>
</span></code></pre></div>
<p>Or:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a>Error: jwt expired
</span></code></pre></div>
<h4 id="common-causes_3">Common Causes<a class="headerlink" href="#common-causes_3" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Access token expired</strong> - Normal after 15 minutes inactive</li>
<li><strong>Refresh token expired</strong> - After 7 days</li>
<li><strong>System clock skew</strong> - Server/client time difference</li>
</ol>
<h4 id="solutions_3">Solutions<a class="headerlink" href="#solutions_3" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Frontend auto-refresh</strong></p>
<p>Frontend automatically refreshes tokens on 401. If this fails:</p>
<div class="language-javascript highlight"><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="c1">// Check refresh token in localStorage</span>
</span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">storage</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s1">&#39;auth-storage&#39;</span><span class="p">));</span>
</span><span id="__span-15-3"><a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Has refresh token:&#39;</span><span class="p">,</span><span class="w"> </span><span class="o">!!</span><span class="nx">storage</span><span class="o">?</span><span class="p">.</span><span class="nx">state</span><span class="o">?</span><span class="p">.</span><span class="nx">refreshToken</span><span class="p">);</span>
</span><span id="__span-15-4"><a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a>
</span><span id="__span-15-5"><a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a><span class="c1">// If missing, need to log in again</span>
</span></code></pre></div>
<p><strong>Solution 2: Manual refresh</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-16-1"><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="c1"># Refresh token via API</span>
</span><span id="__span-16-2"><a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://localhost:4000/api/auth/refresh<span class="w"> </span><span class="se">\</span>
</span><span id="__span-16-3"><a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-16-4"><a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;refreshToken&quot;: &quot;YOUR_REFRESH_TOKEN&quot;}&#39;</span>
</span><span id="__span-16-5"><a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a>
</span><span id="__span-16-6"><a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a><span class="c1"># Returns new access + refresh tokens</span>
</span></code></pre></div>
<p><strong>Solution 3: Check token expiration</strong></p>
<div class="language-javascript highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="c1">// Decode JWT to see expiration</span>
</span><span id="__span-17-2"><a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&#39;</span><span class="p">;</span>
</span><span id="__span-17-3"><a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a><span class="kd">const</span><span class="w"> </span><span class="nx">payload</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">atob</span><span class="p">(</span><span class="nx">token</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)[</span><span class="mf">1</span><span class="p">]));</span>
</span><span id="__span-17-4"><a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Expires:&#39;</span><span class="p">,</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(</span><span class="nx">payload</span><span class="p">.</span><span class="nx">exp</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1000</span><span class="p">));</span>
</span><span id="__span-17-5"><a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Now:&#39;</span><span class="p">,</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">());</span>
</span></code></pre></div>
<p><strong>Solution 4: Check system time</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="c1"># On server</span>
</span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>api<span class="w"> </span>date
</span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a>
</span><span id="__span-18-4"><a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a><span class="c1"># Should match actual time</span>
</span><span id="__span-18-5"><a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a><span class="c1"># If not, sync clock:</span>
</span><span id="__span-18-6"><a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a>sudo<span class="w"> </span>ntpdate<span class="w"> </span>-s<span class="w"> </span>time.nist.gov
</span></code></pre></div>
<p><strong>Solution 5: Log in again</strong></p>
<p>If refresh token also expired:</p>
<ol>
<li>You'll be redirected to login automatically</li>
<li>Log in with email/password</li>
<li>New tokens issued</li>
</ol>
<h4 id="prevention_3">Prevention<a class="headerlink" href="#prevention_3" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Sliding sessions</strong> - Auto-refresh extends session</li>
<li><strong>Long refresh window</strong> - 7-day refresh token validity</li>
<li><strong>Activity tracking</strong> - Keep track of last activity</li>
<li><strong>Clock sync</strong> - Keep server time accurate</li>
</ul>
<hr />
<h3 id="invalid-token">Invalid Token<a class="headerlink" href="#invalid-token" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟠 High</p>
<h4 id="symptoms_4">Symptoms<a class="headerlink" href="#symptoms_4" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="p">{</span>
</span><span id="__span-19-2"><a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Unauthorized&quot;</span><span class="p">,</span>
</span><span id="__span-19-3"><a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Invalid token&quot;</span>
</span><span id="__span-19-4"><a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a><span class="p">}</span>
</span></code></pre></div>
<p>Or:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-20-1"><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a>Error: jwt malformed
</span><span id="__span-20-2"><a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a>Error: invalid signature
</span><span id="__span-20-3"><a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a>Error: invalid algorithm
</span></code></pre></div>
<h4 id="common-causes_4">Common Causes<a class="headerlink" href="#common-causes_4" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Corrupted token</strong> - LocalStorage corruption</li>
<li><strong>Wrong secret</strong> - JWT_ACCESS_SECRET changed</li>
<li><strong>Tampered token</strong> - Someone modified the token</li>
<li><strong>Format error</strong> - Not a valid JWT</li>
</ol>
<h4 id="solutions_4">Solutions<a class="headerlink" href="#solutions_4" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Verify JWT format</strong></p>
<p>Valid JWT has 3 parts separated by dots:</p>
<div class="language-javascript highlight"><pre><span></span><code><span id="__span-21-1"><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="kd">const</span><span class="w"> </span><span class="nx">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;header.payload.signature&#39;</span><span class="p">;</span>
</span><span id="__span-21-2"><a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">token</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">).</span><span class="nx">length</span><span class="p">);</span><span class="w"> </span><span class="c1">// Should be 3</span>
</span><span id="__span-21-3"><a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a>
</span><span id="__span-21-4"><a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a><span class="c1">// Example valid token:</span>
</span><span id="__span-21-5"><a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a><span class="c1">// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.</span>
</span><span id="__span-21-6"><a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a><span class="c1">// eyJpZCI6IjEyMyIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsInJvbGUiOiJVU0VSIiwiaWF0IjoxNzA4MDAwMDAwLCJleHAiOjE3MDgwMDA5MDB9.</span>
</span><span id="__span-21-7"><a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a><span class="c1">// signature-here</span>
</span></code></pre></div>
<p><strong>Solution 2: Clear localStorage and re-login</strong></p>
<div class="language-javascript highlight"><pre><span></span><code><span id="__span-22-1"><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="c1">// In browser console</span>
</span><span id="__span-22-2"><a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="nx">localStorage</span><span class="p">.</span><span class="nx">clear</span><span class="p">();</span>
</span><span id="__span-22-3"><a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="c1">// Then log in again</span>
</span></code></pre></div>
<p><strong>Solution 3: Verify JWT_ACCESS_SECRET</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-23-1"><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a><span class="c1"># Check API .env</span>
</span><span id="__span-23-2"><a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>api<span class="w"> </span>sh<span class="w"> </span>-c<span class="w"> </span><span class="s1">&#39;echo $JWT_ACCESS_SECRET&#39;</span>
</span><span id="__span-23-3"><a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a>
</span><span id="__span-23-4"><a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a><span class="c1"># Should be:</span>
</span><span id="__span-23-5"><a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a><span class="c1"># - At least 32 characters</span>
</span><span id="__span-23-6"><a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a><span class="c1"># - Never changed (changing invalidates all tokens)</span>
</span><span id="__span-23-7"><a id="__codelineno-23-7" name="__codelineno-23-7" href="#__codelineno-23-7"></a><span class="c1"># - Different from JWT_REFRESH_SECRET</span>
</span></code></pre></div>
<p><strong>Solution 4: Test token verification</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-24-1"><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a><span class="c1"># Test token via API</span>
</span><span id="__span-24-2"><a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a>curl<span class="w"> </span>http://localhost:4000/api/auth/me<span class="w"> </span><span class="se">\</span>
</span><span id="__span-24-3"><a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Authorization: Bearer YOUR_ACCESS_TOKEN&quot;</span>
</span><span id="__span-24-4"><a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a>
</span><span id="__span-24-5"><a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a><span class="c1"># If returns user, token is valid</span>
</span><span id="__span-24-6"><a id="__codelineno-24-6" name="__codelineno-24-6" href="#__codelineno-24-6"></a><span class="c1"># If 401, token is invalid</span>
</span></code></pre></div>
<p><strong>Solution 5: Check API logs</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-25-1"><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><span class="c1"># View token validation errors</span>
</span><span id="__span-25-2"><a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a>docker<span class="w"> </span>compose<span class="w"> </span>logs<span class="w"> </span>api<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-i<span class="w"> </span><span class="s2">&quot;jwt\|token&quot;</span>
</span><span id="__span-25-3"><a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a>
</span><span id="__span-25-4"><a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a><span class="c1"># Common errors:</span>
</span><span id="__span-25-5"><a id="__codelineno-25-5" name="__codelineno-25-5" href="#__codelineno-25-5"></a><span class="c1"># - &quot;jwt malformed&quot; - not a valid JWT format</span>
</span><span id="__span-25-6"><a id="__codelineno-25-6" name="__codelineno-25-6" href="#__codelineno-25-6"></a><span class="c1"># - &quot;invalid signature&quot; - wrong secret or tampered</span>
</span><span id="__span-25-7"><a id="__codelineno-25-7" name="__codelineno-25-7" href="#__codelineno-25-7"></a><span class="c1"># - &quot;invalid algorithm&quot; - algorithm mismatch</span>
</span></code></pre></div>
<h4 id="prevention_4">Prevention<a class="headerlink" href="#prevention_4" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Secure secrets</strong> - Use strong, random secrets</li>
<li><strong>Never change secrets</strong> - Changing logs out all users</li>
<li><strong>Don't expose secrets</strong> - Never commit to git</li>
<li><strong>Token validation</strong> - Validate before using</li>
</ul>
<hr />
<h3 id="token-not-found-in-header">Token Not Found in Header<a class="headerlink" href="#token-not-found-in-header" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟡 Medium</p>
<h4 id="symptoms_5">Symptoms<a class="headerlink" href="#symptoms_5" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-26-1"><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a><span class="p">{</span>
</span><span id="__span-26-2"><a id="__codelineno-26-2" name="__codelineno-26-2" href="#__codelineno-26-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Unauthorized&quot;</span><span class="p">,</span>
</span><span id="__span-26-3"><a id="__codelineno-26-3" name="__codelineno-26-3" href="#__codelineno-26-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;No token provided&quot;</span>
</span><span id="__span-26-4"><a id="__codelineno-26-4" name="__codelineno-26-4" href="#__codelineno-26-4"></a><span class="p">}</span>
</span></code></pre></div>
<p>Or:</p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-27-1"><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a><span class="p">{</span>
</span><span id="__span-27-2"><a id="__codelineno-27-2" name="__codelineno-27-2" href="#__codelineno-27-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Unauthorized&quot;</span><span class="p">,</span>
</span><span id="__span-27-3"><a id="__codelineno-27-3" name="__codelineno-27-3" href="#__codelineno-27-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Invalid authorization header format&quot;</span>
</span><span id="__span-27-4"><a id="__codelineno-27-4" name="__codelineno-27-4" href="#__codelineno-27-4"></a><span class="p">}</span>
</span></code></pre></div>
<h4 id="common-causes_5">Common Causes<a class="headerlink" href="#common-causes_5" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Missing Authorization header</strong> - Header not sent</li>
<li><strong>Wrong header format</strong> - Not "Bearer token"</li>
<li><strong>Token not in localStorage</strong> - User not logged in</li>
<li><strong>API client misconfigured</strong> - axios interceptor not working</li>
</ol>
<h4 id="solutions_5">Solutions<a class="headerlink" href="#solutions_5" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Check if logged in</strong></p>
<div class="language-javascript highlight"><pre><span></span><code><span id="__span-28-1"><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a><span class="c1">// In browser console</span>
</span><span id="__span-28-2"><a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">storage</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s1">&#39;auth-storage&#39;</span><span class="p">));</span>
</span><span id="__span-28-3"><a id="__codelineno-28-3" name="__codelineno-28-3" href="#__codelineno-28-3"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Access token:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">storage</span><span class="o">?</span><span class="p">.</span><span class="nx">state</span><span class="o">?</span><span class="p">.</span><span class="nx">accessToken</span><span class="p">);</span>
</span><span id="__span-28-4"><a id="__codelineno-28-4" name="__codelineno-28-4" href="#__codelineno-28-4"></a>
</span><span id="__span-28-5"><a id="__codelineno-28-5" name="__codelineno-28-5" href="#__codelineno-28-5"></a><span class="c1">// If null, not logged in</span>
</span></code></pre></div>
<p><strong>Solution 2: Verify header format</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-29-1"><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a><span class="c1"># Correct format</span>
</span><span id="__span-29-2"><a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-2"></a>curl<span class="w"> </span>http://localhost:4000/api/users<span class="w"> </span><span class="se">\</span>
</span><span id="__span-29-3"><a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&quot;</span>
</span><span id="__span-29-4"><a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a>
</span><span id="__span-29-5"><a id="__codelineno-29-5" name="__codelineno-29-5" href="#__codelineno-29-5"></a><span class="c1"># Wrong formats:</span>
</span><span id="__span-29-6"><a id="__codelineno-29-6" name="__codelineno-29-6" href="#__codelineno-29-6"></a><span class="c1"># -H &quot;Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&quot; # Missing &quot;Bearer&quot;</span>
</span><span id="__span-29-7"><a id="__codelineno-29-7" name="__codelineno-29-7" href="#__codelineno-29-7"></a><span class="c1"># -H &quot;Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&quot; # Wrong header name</span>
</span><span id="__span-29-8"><a id="__codelineno-29-8" name="__codelineno-29-8" href="#__codelineno-29-8"></a><span class="c1"># -H &quot;Authorization: Token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...&quot; # Wrong prefix</span>
</span></code></pre></div>
<p><strong>Solution 3: Check axios interceptor</strong></p>
<p>In <code>admin/src/lib/api.ts</code>:</p>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-30-1"><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a><span class="c1">// Request interceptor should add token</span>
</span><span id="__span-30-2"><a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a><span class="nx">api</span><span class="p">.</span><span class="nx">interceptors</span><span class="p">.</span><span class="nx">request</span><span class="p">.</span><span class="nx">use</span><span class="p">((</span><span class="nx">config</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-3"><a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">storage</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s1">&#39;auth-storage&#39;</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">&#39;{}&#39;</span><span class="p">);</span>
</span><span id="__span-30-4"><a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">storage</span><span class="o">?</span><span class="p">.</span><span class="nx">state</span><span class="o">?</span><span class="p">.</span><span class="nx">accessToken</span><span class="p">;</span>
</span><span id="__span-30-5"><a id="__codelineno-30-5" name="__codelineno-30-5" href="#__codelineno-30-5"></a>
</span><span id="__span-30-6"><a id="__codelineno-30-6" name="__codelineno-30-6" href="#__codelineno-30-6"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">token</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-7"><a id="__codelineno-30-7" name="__codelineno-30-7" href="#__codelineno-30-7"></a><span class="w"> </span><span class="nx">config</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">Authorization</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sb">`Bearer </span><span class="si">${</span><span class="nx">token</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span><span id="__span-30-8"><a id="__codelineno-30-8" name="__codelineno-30-8" href="#__codelineno-30-8"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-30-9"><a id="__codelineno-30-9" name="__codelineno-30-9" href="#__codelineno-30-9"></a>
</span><span id="__span-30-10"><a id="__codelineno-30-10" name="__codelineno-30-10" href="#__codelineno-30-10"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">config</span><span class="p">;</span>
</span><span id="__span-30-11"><a id="__codelineno-30-11" name="__codelineno-30-11" href="#__codelineno-30-11"></a><span class="p">});</span>
</span></code></pre></div>
<p><strong>Solution 4: Test with curl</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-31-1"><a id="__codelineno-31-1" name="__codelineno-31-1" href="#__codelineno-31-1"></a><span class="c1"># Get token from localStorage (browser console)</span>
</span><span id="__span-31-2"><a id="__codelineno-31-2" name="__codelineno-31-2" href="#__codelineno-31-2"></a>const<span class="w"> </span><span class="nv">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>JSON.parse<span class="o">(</span>localStorage.getItem<span class="o">(</span><span class="s1">&#39;auth-storage&#39;</span><span class="o">))</span>.state.accessToken<span class="p">;</span>
</span><span id="__span-31-3"><a id="__codelineno-31-3" name="__codelineno-31-3" href="#__codelineno-31-3"></a>console.log<span class="o">(</span>token<span class="o">)</span><span class="p">;</span>
</span><span id="__span-31-4"><a id="__codelineno-31-4" name="__codelineno-31-4" href="#__codelineno-31-4"></a>
</span><span id="__span-31-5"><a id="__codelineno-31-5" name="__codelineno-31-5" href="#__codelineno-31-5"></a><span class="c1"># Test with curl</span>
</span><span id="__span-31-6"><a id="__codelineno-31-6" name="__codelineno-31-6" href="#__codelineno-31-6"></a>curl<span class="w"> </span>http://localhost:4000/api/users<span class="w"> </span><span class="se">\</span>
</span><span id="__span-31-7"><a id="__codelineno-31-7" name="__codelineno-31-7" href="#__codelineno-31-7"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Authorization: Bearer [paste-token-here]&quot;</span>
</span></code></pre></div>
<p><strong>Solution 5: Log in again</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-32-1"><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a><span class="c1"># If all else fails, log out and log in</span>
</span><span id="__span-32-2"><a id="__codelineno-32-2" name="__codelineno-32-2" href="#__codelineno-32-2"></a>localStorage.clear<span class="o">()</span><span class="p">;</span>
</span><span id="__span-32-3"><a id="__codelineno-32-3" name="__codelineno-32-3" href="#__codelineno-32-3"></a><span class="c1"># Navigate to /login</span>
</span></code></pre></div>
<h4 id="prevention_5">Prevention<a class="headerlink" href="#prevention_5" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>axios interceptor</strong> - Automatically add token to requests</li>
<li><strong>Error handling</strong> - Redirect to login on 401</li>
<li><strong>Token persistence</strong> - Store token in localStorage</li>
<li><strong>Testing</strong> - Test auth flow regularly</li>
</ul>
<hr />
<h3 id="refresh-token-invalid">Refresh Token Invalid<a class="headerlink" href="#refresh-token-invalid" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟠 High</p>
<h4 id="symptoms_6">Symptoms<a class="headerlink" href="#symptoms_6" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-33-1"><a id="__codelineno-33-1" name="__codelineno-33-1" href="#__codelineno-33-1"></a><span class="p">{</span>
</span><span id="__span-33-2"><a id="__codelineno-33-2" name="__codelineno-33-2" href="#__codelineno-33-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Unauthorized&quot;</span><span class="p">,</span>
</span><span id="__span-33-3"><a id="__codelineno-33-3" name="__codelineno-33-3" href="#__codelineno-33-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Invalid refresh token&quot;</span>
</span><span id="__span-33-4"><a id="__codelineno-33-4" name="__codelineno-33-4" href="#__codelineno-33-4"></a><span class="p">}</span>
</span></code></pre></div>
<p>Auto-refresh fails, user logged out.</p>
<h4 id="common-causes_6">Common Causes<a class="headerlink" href="#common-causes_6" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Refresh token expired</strong> - Older than 7 days</li>
<li><strong>Token revoked</strong> - User logged out explicitly</li>
<li><strong>Token not in database</strong> - Database was reset</li>
<li><strong>Token rotation</strong> - Token already used (consumed)</li>
</ol>
<h4 id="solutions_6">Solutions<a class="headerlink" href="#solutions_6" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Check refresh token in database</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-34-1"><a id="__codelineno-34-1" name="__codelineno-34-1" href="#__codelineno-34-1"></a><span class="c1"># Find refresh token</span>
</span><span id="__span-34-2"><a id="__codelineno-34-2" name="__codelineno-34-2" href="#__codelineno-34-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-34-3"><a id="__codelineno-34-3" name="__codelineno-34-3" href="#__codelineno-34-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT id, \&quot;userId\&quot;, \&quot;expiresAt\&quot;, \&quot;createdAt\&quot; FROM \&quot;RefreshToken\&quot;</span>
</span><span id="__span-34-4"><a id="__codelineno-34-4" name="__codelineno-34-4" href="#__codelineno-34-4"></a><span class="s2"> WHERE token = &#39;YOUR_REFRESH_TOKEN_HASH&#39;;&quot;</span>
</span><span id="__span-34-5"><a id="__codelineno-34-5" name="__codelineno-34-5" href="#__codelineno-34-5"></a>
</span><span id="__span-34-6"><a id="__codelineno-34-6" name="__codelineno-34-6" href="#__codelineno-34-6"></a><span class="c1"># If no result, token doesn&#39;t exist (revoked or expired)</span>
</span></code></pre></div>
<p><strong>Solution 2: Check expiration</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-35-1"><a id="__codelineno-35-1" name="__codelineno-35-1" href="#__codelineno-35-1"></a><span class="c1"># Find all refresh tokens for user</span>
</span><span id="__span-35-2"><a id="__codelineno-35-2" name="__codelineno-35-2" href="#__codelineno-35-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-35-3"><a id="__codelineno-35-3" name="__codelineno-35-3" href="#__codelineno-35-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT id, \&quot;expiresAt\&quot;, \&quot;createdAt\&quot; FROM \&quot;RefreshToken\&quot;</span>
</span><span id="__span-35-4"><a id="__codelineno-35-4" name="__codelineno-35-4" href="#__codelineno-35-4"></a><span class="s2"> WHERE \&quot;userId\&quot; = &#39;USER_UUID&#39;</span>
</span><span id="__span-35-5"><a id="__codelineno-35-5" name="__codelineno-35-5" href="#__codelineno-35-5"></a><span class="s2"> ORDER BY \&quot;createdAt\&quot; DESC;&quot;</span>
</span><span id="__span-35-6"><a id="__codelineno-35-6" name="__codelineno-35-6" href="#__codelineno-35-6"></a>
</span><span id="__span-35-7"><a id="__codelineno-35-7" name="__codelineno-35-7" href="#__codelineno-35-7"></a><span class="c1"># Check if expiresAt &lt; NOW()</span>
</span></code></pre></div>
<p><strong>Solution 3: Log in again</strong></p>
<p>Refresh token can't be renewed. Must log in with email/password:</p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-36-1"><a id="__codelineno-36-1" name="__codelineno-36-1" href="#__codelineno-36-1"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://localhost:4000/api/auth/login<span class="w"> </span><span class="se">\</span>
</span><span id="__span-36-2"><a id="__codelineno-36-2" name="__codelineno-36-2" href="#__codelineno-36-2"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-36-3"><a id="__codelineno-36-3" name="__codelineno-36-3" href="#__codelineno-36-3"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{</span>
</span><span id="__span-36-4"><a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a><span class="s1"> &quot;email&quot;: &quot;user@example.com&quot;,</span>
</span><span id="__span-36-5"><a id="__codelineno-36-5" name="__codelineno-36-5" href="#__codelineno-36-5"></a><span class="s1"> &quot;password&quot;: &quot;SecurePass123!&quot;</span>
</span><span id="__span-36-6"><a id="__codelineno-36-6" name="__codelineno-36-6" href="#__codelineno-36-6"></a><span class="s1"> }&#39;</span>
</span></code></pre></div>
<p><strong>Solution 4: Clear old refresh tokens</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-37-1"><a id="__codelineno-37-1" name="__codelineno-37-1" href="#__codelineno-37-1"></a><span class="c1"># Delete expired refresh tokens</span>
</span><span id="__span-37-2"><a id="__codelineno-37-2" name="__codelineno-37-2" href="#__codelineno-37-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-37-3"><a id="__codelineno-37-3" name="__codelineno-37-3" href="#__codelineno-37-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;DELETE FROM \&quot;RefreshToken\&quot; WHERE \&quot;expiresAt\&quot; &lt; NOW();&quot;</span>
</span><span id="__span-37-4"><a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a>
</span><span id="__span-37-5"><a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a><span class="c1"># Or delete all refresh tokens for user (logs out all devices)</span>
</span><span id="__span-37-6"><a id="__codelineno-37-6" name="__codelineno-37-6" href="#__codelineno-37-6"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-37-7"><a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;DELETE FROM \&quot;RefreshToken\&quot; WHERE \&quot;userId\&quot; = &#39;USER_UUID&#39;;&quot;</span>
</span></code></pre></div>
<h4 id="prevention_6">Prevention<a class="headerlink" href="#prevention_6" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Long expiration</strong> - 7-day refresh token validity</li>
<li><strong>Token rotation</strong> - New refresh token on each refresh</li>
<li><strong>Cleanup job</strong> - Delete expired tokens periodically</li>
<li><strong>Multi-device support</strong> - Multiple refresh tokens per user</li>
</ul>
<hr />
<h2 id="permission-errors">Permission Errors<a class="headerlink" href="#permission-errors" title="Permanent link">&para;</a></h2>
<h3 id="insufficient-permissions">Insufficient Permissions<a class="headerlink" href="#insufficient-permissions" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟡 Medium</p>
<h4 id="symptoms_7">Symptoms<a class="headerlink" href="#symptoms_7" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-38-1"><a id="__codelineno-38-1" name="__codelineno-38-1" href="#__codelineno-38-1"></a><span class="p">{</span>
</span><span id="__span-38-2"><a id="__codelineno-38-2" name="__codelineno-38-2" href="#__codelineno-38-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Forbidden&quot;</span><span class="p">,</span>
</span><span id="__span-38-3"><a id="__codelineno-38-3" name="__codelineno-38-3" href="#__codelineno-38-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Insufficient permissions&quot;</span>
</span><span id="__span-38-4"><a id="__codelineno-38-4" name="__codelineno-38-4" href="#__codelineno-38-4"></a><span class="p">}</span>
</span></code></pre></div>
<p>Or role-specific:</p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-39-1"><a id="__codelineno-39-1" name="__codelineno-39-1" href="#__codelineno-39-1"></a><span class="p">{</span>
</span><span id="__span-39-2"><a id="__codelineno-39-2" name="__codelineno-39-2" href="#__codelineno-39-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Forbidden&quot;</span><span class="p">,</span>
</span><span id="__span-39-3"><a id="__codelineno-39-3" name="__codelineno-39-3" href="#__codelineno-39-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Requires one of: SUPER_ADMIN, MAP_ADMIN&quot;</span>
</span><span id="__span-39-4"><a id="__codelineno-39-4" name="__codelineno-39-4" href="#__codelineno-39-4"></a><span class="p">}</span>
</span></code></pre></div>
<h4 id="common-causes_7">Common Causes<a class="headerlink" href="#common-causes_7" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Wrong role</strong> - User doesn't have required role</li>
<li><strong>TEMP user</strong> - Temporary user trying to access admin features</li>
<li><strong>Feature disabled</strong> - Feature flag not enabled</li>
<li><strong>Endpoint restricted</strong> - Endpoint requires specific role</li>
</ol>
<h4 id="solutions_7">Solutions<a class="headerlink" href="#solutions_7" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Check user role</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-40-1"><a id="__codelineno-40-1" name="__codelineno-40-1" href="#__codelineno-40-1"></a><span class="c1"># View user role</span>
</span><span id="__span-40-2"><a id="__codelineno-40-2" name="__codelineno-40-2" href="#__codelineno-40-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-40-3"><a id="__codelineno-40-3" name="__codelineno-40-3" href="#__codelineno-40-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT email, role FROM \&quot;User\&quot; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span><span id="__span-40-4"><a id="__codelineno-40-4" name="__codelineno-40-4" href="#__codelineno-40-4"></a>
</span><span id="__span-40-5"><a id="__codelineno-40-5" name="__codelineno-40-5" href="#__codelineno-40-5"></a><span class="c1"># Roles:</span>
</span><span id="__span-40-6"><a id="__codelineno-40-6" name="__codelineno-40-6" href="#__codelineno-40-6"></a><span class="c1"># SUPER_ADMIN - full access</span>
</span><span id="__span-40-7"><a id="__codelineno-40-7" name="__codelineno-40-7" href="#__codelineno-40-7"></a><span class="c1"># INFLUENCE_ADMIN - campaigns/responses</span>
</span><span id="__span-40-8"><a id="__codelineno-40-8" name="__codelineno-40-8" href="#__codelineno-40-8"></a><span class="c1"># MAP_ADMIN - locations/cuts/shifts</span>
</span><span id="__span-40-9"><a id="__codelineno-40-9" name="__codelineno-40-9" href="#__codelineno-40-9"></a><span class="c1"># USER - public content + canvass</span>
</span><span id="__span-40-10"><a id="__codelineno-40-10" name="__codelineno-40-10" href="#__codelineno-40-10"></a><span class="c1"># TEMP - very limited</span>
</span></code></pre></div>
<p><strong>Solution 2: Update user role</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-41-1"><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a><span class="c1"># Via Prisma Studio (recommended)</span>
</span><span id="__span-41-2"><a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>api<span class="w"> </span>npx<span class="w"> </span>prisma<span class="w"> </span>studio
</span><span id="__span-41-3"><a id="__codelineno-41-3" name="__codelineno-41-3" href="#__codelineno-41-3"></a><span class="c1"># Navigate to User table, edit role field</span>
</span><span id="__span-41-4"><a id="__codelineno-41-4" name="__codelineno-41-4" href="#__codelineno-41-4"></a>
</span><span id="__span-41-5"><a id="__codelineno-41-5" name="__codelineno-41-5" href="#__codelineno-41-5"></a><span class="c1"># Or via SQL</span>
</span><span id="__span-41-6"><a id="__codelineno-41-6" name="__codelineno-41-6" href="#__codelineno-41-6"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-41-7"><a id="__codelineno-41-7" name="__codelineno-41-7" href="#__codelineno-41-7"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE \&quot;User\&quot; SET role = &#39;MAP_ADMIN&#39; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span></code></pre></div>
<p><strong>Solution 3: Check endpoint requirements</strong></p>
<p>In API code (<code>api/src/modules/*/routes.ts</code>):</p>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-42-1"><a id="__codelineno-42-1" name="__codelineno-42-1" href="#__codelineno-42-1"></a><span class="c1">// Example from campaigns.routes.ts</span>
</span><span id="__span-42-2"><a id="__codelineno-42-2" name="__codelineno-42-2" href="#__codelineno-42-2"></a><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span>
</span><span id="__span-42-3"><a id="__codelineno-42-3" name="__codelineno-42-3" href="#__codelineno-42-3"></a><span class="w"> </span><span class="nx">authenticate</span><span class="p">,</span><span class="w"> </span><span class="c1">// Must be logged in</span>
</span><span id="__span-42-4"><a id="__codelineno-42-4" name="__codelineno-42-4" href="#__codelineno-42-4"></a><span class="w"> </span><span class="nx">requireRole</span><span class="p">(</span><span class="s1">&#39;SUPER_ADMIN&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;INFLUENCE_ADMIN&#39;</span><span class="p">),</span><span class="w"> </span><span class="c1">// Must be admin</span>
</span><span id="__span-42-5"><a id="__codelineno-42-5" name="__codelineno-42-5" href="#__codelineno-42-5"></a><span class="w"> </span><span class="nx">validate</span><span class="p">(</span><span class="nx">createCampaignSchema</span><span class="p">),</span>
</span><span id="__span-42-6"><a id="__codelineno-42-6" name="__codelineno-42-6" href="#__codelineno-42-6"></a><span class="w"> </span><span class="nx">campaignsController</span><span class="p">.</span><span class="nx">create</span>
</span><span id="__span-42-7"><a id="__codelineno-42-7" name="__codelineno-42-7" href="#__codelineno-42-7"></a><span class="p">);</span>
</span></code></pre></div>
<p><strong>Solution 4: Verify feature flags</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-43-1"><a id="__codelineno-43-1" name="__codelineno-43-1" href="#__codelineno-43-1"></a><span class="c1"># Check .env for feature flags</span>
</span><span id="__span-43-2"><a id="__codelineno-43-2" name="__codelineno-43-2" href="#__codelineno-43-2"></a>cat<span class="w"> </span>.env<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>ENABLE
</span><span id="__span-43-3"><a id="__codelineno-43-3" name="__codelineno-43-3" href="#__codelineno-43-3"></a>
</span><span id="__span-43-4"><a id="__codelineno-43-4" name="__codelineno-43-4" href="#__codelineno-43-4"></a><span class="c1"># Example:</span>
</span><span id="__span-43-5"><a id="__codelineno-43-5" name="__codelineno-43-5" href="#__codelineno-43-5"></a><span class="nv">ENABLE_MEDIA_FEATURES</span><span class="o">=</span><span class="nb">true</span>
</span><span id="__span-43-6"><a id="__codelineno-43-6" name="__codelineno-43-6" href="#__codelineno-43-6"></a><span class="nv">LISTMONK_SYNC_ENABLED</span><span class="o">=</span><span class="nb">true</span>
</span></code></pre></div>
<p><strong>Solution 5: Check TEMP user restrictions</strong></p>
<p>TEMP users are created during shift signup and have very limited permissions:</p>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-44-1"><a id="__codelineno-44-1" name="__codelineno-44-1" href="#__codelineno-44-1"></a><span class="c1">// TEMP users blocked by requireNonTemp middleware</span>
</span><span id="__span-44-2"><a id="__codelineno-44-2" name="__codelineno-44-2" href="#__codelineno-44-2"></a><span class="nx">router</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/my-data&#39;</span><span class="p">,</span>
</span><span id="__span-44-3"><a id="__codelineno-44-3" name="__codelineno-44-3" href="#__codelineno-44-3"></a><span class="w"> </span><span class="nx">authenticate</span><span class="p">,</span>
</span><span id="__span-44-4"><a id="__codelineno-44-4" name="__codelineno-44-4" href="#__codelineno-44-4"></a><span class="w"> </span><span class="nx">requireNonTemp</span><span class="p">,</span><span class="w"> </span><span class="c1">// Blocks TEMP users</span>
</span><span id="__span-44-5"><a id="__codelineno-44-5" name="__codelineno-44-5" href="#__codelineno-44-5"></a><span class="w"> </span><span class="nx">controller</span><span class="p">.</span><span class="nx">getData</span>
</span><span id="__span-44-6"><a id="__codelineno-44-6" name="__codelineno-44-6" href="#__codelineno-44-6"></a><span class="p">);</span>
</span></code></pre></div>
<p>To convert TEMP to USER:</p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-45-1"><a id="__codelineno-45-1" name="__codelineno-45-1" href="#__codelineno-45-1"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-45-2"><a id="__codelineno-45-2" name="__codelineno-45-2" href="#__codelineno-45-2"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE \&quot;User\&quot; SET role = &#39;USER&#39; WHERE email = &#39;temp@example.com&#39;;&quot;</span>
</span></code></pre></div>
<h4 id="prevention_7">Prevention<a class="headerlink" href="#prevention_7" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Clear role descriptions</strong> - Document what each role can do</li>
<li><strong>Role matrix</strong> - Table showing role → permission mapping</li>
<li><strong>Upgrade flow</strong> - Easy way for users to upgrade from TEMP to USER</li>
<li><strong>Helpful errors</strong> - Show which role is required</li>
</ul>
<hr />
<h3 id="role-restrictions">Role Restrictions<a class="headerlink" href="#role-restrictions" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟢 Low</p>
<h4 id="symptoms_8">Symptoms<a class="headerlink" href="#symptoms_8" title="Permanent link">&para;</a></h4>
<p>User logged in but can't access certain features.</p>
<h4 id="common-causes_8">Common Causes<a class="headerlink" href="#common-causes_8" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Not enough permissions</strong> - Role too low for feature</li>
<li><strong>Feature flag</strong> - Feature not enabled</li>
<li><strong>TEMP user</strong> - Temporary account with restrictions</li>
</ol>
<h4 id="solutions_8">Solutions<a class="headerlink" href="#solutions_8" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: View role permissions</strong></p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>SUPER_ADMIN</th>
<th>INFLUENCE_ADMIN</th>
<th>MAP_ADMIN</th>
<th>USER</th>
<th>TEMP</th>
</tr>
</thead>
<tbody>
<tr>
<td>User management</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Settings</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Campaigns</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Responses</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Email queue</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Locations</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Cuts</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Shifts</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Canvass dashboard</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Public campaigns</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Public shifts</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Volunteer canvass</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p><strong>Solution 2: Request role upgrade</strong></p>
<p>If you need higher permissions:
1. Contact system administrator
2. Explain why you need the role
3. Wait for approval and role change</p>
<p><strong>Solution 3: Create admin account</strong></p>
<p>For first admin (if none exist):</p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-46-1"><a id="__codelineno-46-1" name="__codelineno-46-1" href="#__codelineno-46-1"></a><span class="c1"># Connect to database</span>
</span><span id="__span-46-2"><a id="__codelineno-46-2" name="__codelineno-46-2" href="#__codelineno-46-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2
</span><span id="__span-46-3"><a id="__codelineno-46-3" name="__codelineno-46-3" href="#__codelineno-46-3"></a>
</span><span id="__span-46-4"><a id="__codelineno-46-4" name="__codelineno-46-4" href="#__codelineno-46-4"></a><span class="c1"># Create SUPER_ADMIN</span>
</span><span id="__span-46-5"><a id="__codelineno-46-5" name="__codelineno-46-5" href="#__codelineno-46-5"></a><span class="c1"># (Password must be pre-hashed with bcrypt)</span>
</span><span id="__span-46-6"><a id="__codelineno-46-6" name="__codelineno-46-6" href="#__codelineno-46-6"></a>INSERT<span class="w"> </span>INTO<span class="w"> </span><span class="s2">&quot;User&quot;</span><span class="w"> </span><span class="o">(</span>id,<span class="w"> </span>email,<span class="w"> </span>password,<span class="w"> </span>name,<span class="w"> </span>role<span class="o">)</span>
</span><span id="__span-46-7"><a id="__codelineno-46-7" name="__codelineno-46-7" href="#__codelineno-46-7"></a>VALUES<span class="w"> </span><span class="o">(</span>
</span><span id="__span-46-8"><a id="__codelineno-46-8" name="__codelineno-46-8" href="#__codelineno-46-8"></a><span class="w"> </span>gen_random_uuid<span class="o">()</span>,
</span><span id="__span-46-9"><a id="__codelineno-46-9" name="__codelineno-46-9" href="#__codelineno-46-9"></a><span class="w"> </span><span class="s1">&#39;admin@example.com&#39;</span>,
</span><span id="__span-46-10"><a id="__codelineno-46-10" name="__codelineno-46-10" href="#__codelineno-46-10"></a><span class="w"> </span><span class="s1">&#39;$2a$10$...&#39;</span>,<span class="w"> </span>--<span class="w"> </span>bcrypt<span class="w"> </span><span class="nb">hash</span><span class="w"> </span>of<span class="w"> </span><span class="s1">&#39;Admin123!&#39;</span>
</span><span id="__span-46-11"><a id="__codelineno-46-11" name="__codelineno-46-11" href="#__codelineno-46-11"></a><span class="w"> </span><span class="s1">&#39;System Admin&#39;</span>,
</span><span id="__span-46-12"><a id="__codelineno-46-12" name="__codelineno-46-12" href="#__codelineno-46-12"></a><span class="w"> </span><span class="s1">&#39;SUPER_ADMIN&#39;</span>
</span><span id="__span-46-13"><a id="__codelineno-46-13" name="__codelineno-46-13" href="#__codelineno-46-13"></a><span class="o">)</span><span class="p">;</span>
</span></code></pre></div>
<h4 id="prevention_8">Prevention<a class="headerlink" href="#prevention_8" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Document roles</strong> - Clear description of each role</li>
<li><strong>Role request process</strong> - Easy way to request role upgrade</li>
<li><strong>Audit trail</strong> - Log role changes</li>
<li><strong>Principle of least privilege</strong> - Give minimum role needed</li>
</ul>
<hr />
<h2 id="session-issues">Session Issues<a class="headerlink" href="#session-issues" title="Permanent link">&para;</a></h2>
<h3 id="session-timeout">Session Timeout<a class="headerlink" href="#session-timeout" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟢 Low</p>
<h4 id="symptoms_9">Symptoms<a class="headerlink" href="#symptoms_9" title="Permanent link">&para;</a></h4>
<p>User inactive for a while, then gets logged out.</p>
<h4 id="current-behavior">Current Behavior<a class="headerlink" href="#current-behavior" title="Permanent link">&para;</a></h4>
<p>V2 uses JWT tokens (not sessions):
- <strong>Access token</strong> expires after 15 minutes
- <strong>Refresh token</strong> expires after 7 days
- Auto-refresh on API calls extends session</p>
<h4 id="solutions_9">Solutions<a class="headerlink" href="#solutions_9" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Configure token expiration</strong></p>
<p>In <code>.env</code>:</p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-47-1"><a id="__codelineno-47-1" name="__codelineno-47-1" href="#__codelineno-47-1"></a><span class="c1"># Access token (default: 15m)</span>
</span><span id="__span-47-2"><a id="__codelineno-47-2" name="__codelineno-47-2" href="#__codelineno-47-2"></a><span class="nv">JWT_ACCESS_EXPIRATION</span><span class="o">=</span>30m
</span><span id="__span-47-3"><a id="__codelineno-47-3" name="__codelineno-47-3" href="#__codelineno-47-3"></a>
</span><span id="__span-47-4"><a id="__codelineno-47-4" name="__codelineno-47-4" href="#__codelineno-47-4"></a><span class="c1"># Refresh token (default: 7d)</span>
</span><span id="__span-47-5"><a id="__codelineno-47-5" name="__codelineno-47-5" href="#__codelineno-47-5"></a><span class="nv">JWT_REFRESH_EXPIRATION</span><span class="o">=</span>14d
</span></code></pre></div>
<p>Restart API:</p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-48-1"><a id="__codelineno-48-1" name="__codelineno-48-1" href="#__codelineno-48-1"></a>docker<span class="w"> </span>compose<span class="w"> </span>restart<span class="w"> </span>api
</span></code></pre></div>
<p><strong>Solution 2: Implement activity tracking</strong></p>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-49-1"><a id="__codelineno-49-1" name="__codelineno-49-1" href="#__codelineno-49-1"></a><span class="c1">// In frontend, track last activity</span>
</span><span id="__span-49-2"><a id="__codelineno-49-2" name="__codelineno-49-2" href="#__codelineno-49-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">updateActivity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-49-3"><a id="__codelineno-49-3" name="__codelineno-49-3" href="#__codelineno-49-3"></a><span class="w"> </span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="s1">&#39;lastActivity&#39;</span><span class="p">,</span><span class="w"> </span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">().</span><span class="nx">toString</span><span class="p">());</span>
</span><span id="__span-49-4"><a id="__codelineno-49-4" name="__codelineno-49-4" href="#__codelineno-49-4"></a><span class="p">};</span>
</span><span id="__span-49-5"><a id="__codelineno-49-5" name="__codelineno-49-5" href="#__codelineno-49-5"></a>
</span><span id="__span-49-6"><a id="__codelineno-49-6" name="__codelineno-49-6" href="#__codelineno-49-6"></a><span class="c1">// On any user action</span>
</span><span id="__span-49-7"><a id="__codelineno-49-7" name="__codelineno-49-7" href="#__codelineno-49-7"></a><span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">updateActivity</span><span class="p">);</span>
</span><span id="__span-49-8"><a id="__codelineno-49-8" name="__codelineno-49-8" href="#__codelineno-49-8"></a><span class="nb">document</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;keypress&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">updateActivity</span><span class="p">);</span>
</span><span id="__span-49-9"><a id="__codelineno-49-9" name="__codelineno-49-9" href="#__codelineno-49-9"></a>
</span><span id="__span-49-10"><a id="__codelineno-49-10" name="__codelineno-49-10" href="#__codelineno-49-10"></a><span class="c1">// Check on load</span>
</span><span id="__span-49-11"><a id="__codelineno-49-11" name="__codelineno-49-11" href="#__codelineno-49-11"></a><span class="nx">useEffect</span><span class="p">(()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-49-12"><a id="__codelineno-49-12" name="__codelineno-49-12" href="#__codelineno-49-12"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">lastActivity</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">parseInt</span><span class="p">(</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="s1">&#39;lastActivity&#39;</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">&#39;0&#39;</span><span class="p">);</span>
</span><span id="__span-49-13"><a id="__codelineno-49-13" name="__codelineno-49-13" href="#__codelineno-49-13"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">now</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">();</span>
</span><span id="__span-49-14"><a id="__codelineno-49-14" name="__codelineno-49-14" href="#__codelineno-49-14"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">thirtyMinutes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">30</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">60</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1000</span><span class="p">;</span>
</span><span id="__span-49-15"><a id="__codelineno-49-15" name="__codelineno-49-15" href="#__codelineno-49-15"></a>
</span><span id="__span-49-16"><a id="__codelineno-49-16" name="__codelineno-49-16" href="#__codelineno-49-16"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">now</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">lastActivity</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="nx">thirtyMinutes</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-49-17"><a id="__codelineno-49-17" name="__codelineno-49-17" href="#__codelineno-49-17"></a><span class="w"> </span><span class="c1">// Log out due to inactivity</span>
</span><span id="__span-49-18"><a id="__codelineno-49-18" name="__codelineno-49-18" href="#__codelineno-49-18"></a><span class="w"> </span><span class="nx">authStore</span><span class="p">.</span><span class="nx">logout</span><span class="p">();</span>
</span><span id="__span-49-19"><a id="__codelineno-49-19" name="__codelineno-49-19" href="#__codelineno-49-19"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-49-20"><a id="__codelineno-49-20" name="__codelineno-49-20" href="#__codelineno-49-20"></a><span class="p">},</span><span class="w"> </span><span class="p">[]);</span>
</span></code></pre></div>
<h4 id="prevention_9">Prevention<a class="headerlink" href="#prevention_9" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Sliding sessions</strong> - Auto-refresh extends session</li>
<li><strong>Long refresh window</strong> - 7-day default</li>
<li><strong>Activity tracking</strong> - Reset timeout on activity</li>
<li><strong>Warning before logout</strong> - Show countdown before timeout</li>
</ul>
<hr />
<h3 id="multiple-device-conflicts">Multiple Device Conflicts<a class="headerlink" href="#multiple-device-conflicts" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟢 Low</p>
<h4 id="symptoms_10">Symptoms<a class="headerlink" href="#symptoms_10" title="Permanent link">&para;</a></h4>
<p>User logged in on multiple devices, behavior inconsistent.</p>
<h4 id="current-behavior_1">Current Behavior<a class="headerlink" href="#current-behavior_1" title="Permanent link">&para;</a></h4>
<p>V2 supports multiple devices:
- Each login creates new refresh token
- All devices stay logged in independently
- No device limit by default</p>
<h4 id="solutions_10">Solutions<a class="headerlink" href="#solutions_10" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: View user's devices</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-50-1"><a id="__codelineno-50-1" name="__codelineno-50-1" href="#__codelineno-50-1"></a><span class="c1"># List all refresh tokens for user</span>
</span><span id="__span-50-2"><a id="__codelineno-50-2" name="__codelineno-50-2" href="#__codelineno-50-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-50-3"><a id="__codelineno-50-3" name="__codelineno-50-3" href="#__codelineno-50-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT id, \&quot;createdAt\&quot;, \&quot;expiresAt\&quot; FROM \&quot;RefreshToken\&quot;</span>
</span><span id="__span-50-4"><a id="__codelineno-50-4" name="__codelineno-50-4" href="#__codelineno-50-4"></a><span class="s2"> WHERE \&quot;userId\&quot; = &#39;USER_UUID&#39;</span>
</span><span id="__span-50-5"><a id="__codelineno-50-5" name="__codelineno-50-5" href="#__codelineno-50-5"></a><span class="s2"> ORDER BY \&quot;createdAt\&quot; DESC;&quot;</span>
</span><span id="__span-50-6"><a id="__codelineno-50-6" name="__codelineno-50-6" href="#__codelineno-50-6"></a>
</span><span id="__span-50-7"><a id="__codelineno-50-7" name="__codelineno-50-7" href="#__codelineno-50-7"></a><span class="c1"># Each row = one device/session</span>
</span></code></pre></div>
<p><strong>Solution 2: Log out all devices</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-51-1"><a id="__codelineno-51-1" name="__codelineno-51-1" href="#__codelineno-51-1"></a><span class="c1"># Delete all refresh tokens for user</span>
</span><span id="__span-51-2"><a id="__codelineno-51-2" name="__codelineno-51-2" href="#__codelineno-51-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-51-3"><a id="__codelineno-51-3" name="__codelineno-51-3" href="#__codelineno-51-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;DELETE FROM \&quot;RefreshToken\&quot; WHERE \&quot;userId\&quot; = &#39;USER_UUID&#39;;&quot;</span>
</span><span id="__span-51-4"><a id="__codelineno-51-4" name="__codelineno-51-4" href="#__codelineno-51-4"></a>
</span><span id="__span-51-5"><a id="__codelineno-51-5" name="__codelineno-51-5" href="#__codelineno-51-5"></a><span class="c1"># User must log in again on all devices</span>
</span></code></pre></div>
<p><strong>Solution 3: Log out specific device</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-52-1"><a id="__codelineno-52-1" name="__codelineno-52-1" href="#__codelineno-52-1"></a><span class="c1"># Delete specific refresh token</span>
</span><span id="__span-52-2"><a id="__codelineno-52-2" name="__codelineno-52-2" href="#__codelineno-52-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-52-3"><a id="__codelineno-52-3" name="__codelineno-52-3" href="#__codelineno-52-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;DELETE FROM \&quot;RefreshToken\&quot; WHERE id = &#39;REFRESH_TOKEN_UUID&#39;;&quot;</span>
</span></code></pre></div>
<p><strong>Solution 4: Implement device limit</strong></p>
<p>In <code>api/src/modules/auth/auth.service.ts</code>:</p>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-53-1"><a id="__codelineno-53-1" name="__codelineno-53-1" href="#__codelineno-53-1"></a><span class="c1">// After creating refresh token, limit to 5 devices</span>
</span><span id="__span-53-2"><a id="__codelineno-53-2" name="__codelineno-53-2" href="#__codelineno-53-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">userTokens</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">refreshToken</span><span class="p">.</span><span class="nx">findMany</span><span class="p">({</span>
</span><span id="__span-53-3"><a id="__codelineno-53-3" name="__codelineno-53-3" href="#__codelineno-53-3"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">userId</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-53-4"><a id="__codelineno-53-4" name="__codelineno-53-4" href="#__codelineno-53-4"></a><span class="w"> </span><span class="nx">orderBy</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">createdAt</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;desc&#39;</span><span class="w"> </span><span class="p">}</span>
</span><span id="__span-53-5"><a id="__codelineno-53-5" name="__codelineno-53-5" href="#__codelineno-53-5"></a><span class="p">});</span>
</span><span id="__span-53-6"><a id="__codelineno-53-6" name="__codelineno-53-6" href="#__codelineno-53-6"></a>
</span><span id="__span-53-7"><a id="__codelineno-53-7" name="__codelineno-53-7" href="#__codelineno-53-7"></a><span class="c1">// Delete oldest tokens if &gt; 5</span>
</span><span id="__span-53-8"><a id="__codelineno-53-8" name="__codelineno-53-8" href="#__codelineno-53-8"></a><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">userTokens</span><span class="p">.</span><span class="nx">length</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="mf">5</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-53-9"><a id="__codelineno-53-9" name="__codelineno-53-9" href="#__codelineno-53-9"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">prisma</span><span class="p">.</span><span class="nx">refreshToken</span><span class="p">.</span><span class="nx">deleteMany</span><span class="p">({</span>
</span><span id="__span-53-10"><a id="__codelineno-53-10" name="__codelineno-53-10" href="#__codelineno-53-10"></a><span class="w"> </span><span class="nx">where</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-53-11"><a id="__codelineno-53-11" name="__codelineno-53-11" href="#__codelineno-53-11"></a><span class="w"> </span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">in</span><span class="o">:</span><span class="w"> </span><span class="kt">userTokens.slice</span><span class="p">(</span><span class="mf">5</span><span class="p">).</span><span class="nx">map</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="w"> </span><span class="p">}</span>
</span><span id="__span-53-12"><a id="__codelineno-53-12" name="__codelineno-53-12" href="#__codelineno-53-12"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-53-13"><a id="__codelineno-53-13" name="__codelineno-53-13" href="#__codelineno-53-13"></a><span class="w"> </span><span class="p">});</span>
</span><span id="__span-53-14"><a id="__codelineno-53-14" name="__codelineno-53-14" href="#__codelineno-53-14"></a><span class="p">}</span>
</span></code></pre></div>
<h4 id="prevention_10">Prevention<a class="headerlink" href="#prevention_10" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Device management UI</strong> - Show logged-in devices</li>
<li><strong>Device limit</strong> - Max 5-10 devices per user</li>
<li><strong>Device naming</strong> - Let users name their devices</li>
<li><strong>Remote logout</strong> - Let users log out other devices</li>
</ul>
<hr />
<h2 id="password-reset-issues">Password Reset Issues<a class="headerlink" href="#password-reset-issues" title="Permanent link">&para;</a></h2>
<h3 id="reset-link-expired">Reset Link Expired<a class="headerlink" href="#reset-link-expired" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟢 Low</p>
<h4 id="symptoms_11">Symptoms<a class="headerlink" href="#symptoms_11" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-54-1"><a id="__codelineno-54-1" name="__codelineno-54-1" href="#__codelineno-54-1"></a><span class="p">{</span>
</span><span id="__span-54-2"><a id="__codelineno-54-2" name="__codelineno-54-2" href="#__codelineno-54-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Bad Request&quot;</span><span class="p">,</span>
</span><span id="__span-54-3"><a id="__codelineno-54-3" name="__codelineno-54-3" href="#__codelineno-54-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Password reset link expired or invalid&quot;</span>
</span><span id="__span-54-4"><a id="__codelineno-54-4" name="__codelineno-54-4" href="#__codelineno-54-4"></a><span class="p">}</span>
</span></code></pre></div>
<h4 id="common-causes_9">Common Causes<a class="headerlink" href="#common-causes_9" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Link expired</strong> - Older than 24 hours</li>
<li><strong>Already used</strong> - Link can only be used once</li>
<li><strong>Wrong token</strong> - Token doesn't match database</li>
</ol>
<h4 id="solutions_11">Solutions<a class="headerlink" href="#solutions_11" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Request new reset link</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-55-1"><a id="__codelineno-55-1" name="__codelineno-55-1" href="#__codelineno-55-1"></a><span class="c1"># Via API (if endpoint exists)</span>
</span><span id="__span-55-2"><a id="__codelineno-55-2" name="__codelineno-55-2" href="#__codelineno-55-2"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://localhost:4000/api/auth/forgot-password<span class="w"> </span><span class="se">\</span>
</span><span id="__span-55-3"><a id="__codelineno-55-3" name="__codelineno-55-3" href="#__codelineno-55-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-55-4"><a id="__codelineno-55-4" name="__codelineno-55-4" href="#__codelineno-55-4"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{&quot;email&quot;: &quot;user@example.com&quot;}&#39;</span>
</span></code></pre></div>
<p><strong>Solution 2: Manually reset password</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-56-1"><a id="__codelineno-56-1" name="__codelineno-56-1" href="#__codelineno-56-1"></a><span class="c1"># Generate bcrypt hash</span>
</span><span id="__span-56-2"><a id="__codelineno-56-2" name="__codelineno-56-2" href="#__codelineno-56-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>api<span class="w"> </span>node<span class="w"> </span>-e<span class="w"> </span><span class="s2">&quot;</span>
</span><span id="__span-56-3"><a id="__codelineno-56-3" name="__codelineno-56-3" href="#__codelineno-56-3"></a><span class="s2">const bcrypt = require(&#39;bcryptjs&#39;);</span>
</span><span id="__span-56-4"><a id="__codelineno-56-4" name="__codelineno-56-4" href="#__codelineno-56-4"></a><span class="s2">console.log(bcrypt.hashSync(&#39;NewPassword123!&#39;, 10));</span>
</span><span id="__span-56-5"><a id="__codelineno-56-5" name="__codelineno-56-5" href="#__codelineno-56-5"></a><span class="s2">&quot;</span>
</span><span id="__span-56-6"><a id="__codelineno-56-6" name="__codelineno-56-6" href="#__codelineno-56-6"></a>
</span><span id="__span-56-7"><a id="__codelineno-56-7" name="__codelineno-56-7" href="#__codelineno-56-7"></a><span class="c1"># Update password</span>
</span><span id="__span-56-8"><a id="__codelineno-56-8" name="__codelineno-56-8" href="#__codelineno-56-8"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-56-9"><a id="__codelineno-56-9" name="__codelineno-56-9" href="#__codelineno-56-9"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE \&quot;User\&quot; SET password = &#39;\$2a\$10\$...&#39; WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span></code></pre></div>
<h4 id="prevention_11">Prevention<a class="headerlink" href="#prevention_11" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Longer expiration</strong> - 24-hour expiration is reasonable</li>
<li><strong>Clear messaging</strong> - Tell users link expires</li>
<li><strong>Easy re-request</strong> - Simple way to request new link</li>
</ul>
<div class="admonition note">
<p class="admonition-title">V2 Status</p>
<p>V2 doesn't currently have password reset flow. This section is for future implementation.</p>
</div>
<hr />
<h3 id="email-not-received">Email Not Received<a class="headerlink" href="#email-not-received" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟡 Medium</p>
<h4 id="symptoms_12">Symptoms<a class="headerlink" href="#symptoms_12" title="Permanent link">&para;</a></h4>
<p>User requests password reset but doesn't receive email.</p>
<h4 id="common-causes_10">Common Causes<a class="headerlink" href="#common-causes_10" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Email in spam</strong> - Filtered to spam folder</li>
<li><strong>SMTP issue</strong> - Email sending failed</li>
<li><strong>Wrong email</strong> - Typo in email address</li>
<li><strong>Email delay</strong> - Taking long to deliver</li>
</ol>
<h4 id="solutions_12">Solutions<a class="headerlink" href="#solutions_12" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Check spam folder</strong></p>
<ol>
<li>Check Spam/Junk folder</li>
<li>Check Promotions tab (Gmail)</li>
<li>Check email filters</li>
</ol>
<p><strong>Solution 2: Check email logs</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-57-1"><a id="__codelineno-57-1" name="__codelineno-57-1" href="#__codelineno-57-1"></a><span class="c1"># API logs show email sending</span>
</span><span id="__span-57-2"><a id="__codelineno-57-2" name="__codelineno-57-2" href="#__codelineno-57-2"></a>docker<span class="w"> </span>compose<span class="w"> </span>logs<span class="w"> </span>api<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-i<span class="w"> </span><span class="s2">&quot;email\|smtp&quot;</span>
</span><span id="__span-57-3"><a id="__codelineno-57-3" name="__codelineno-57-3" href="#__codelineno-57-3"></a>
</span><span id="__span-57-4"><a id="__codelineno-57-4" name="__codelineno-57-4" href="#__codelineno-57-4"></a><span class="c1"># Should show:</span>
</span><span id="__span-57-5"><a id="__codelineno-57-5" name="__codelineno-57-5" href="#__codelineno-57-5"></a><span class="c1"># Email sent to user@example.com: Password Reset</span>
</span></code></pre></div>
<p><strong>Solution 3: Check MailHog (dev mode)</strong></p>
<p>If <code>EMAIL_TEST_MODE=true</code>:</p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-58-1"><a id="__codelineno-58-1" name="__codelineno-58-1" href="#__codelineno-58-1"></a><span class="c1"># Open MailHog</span>
</span><span id="__span-58-2"><a id="__codelineno-58-2" name="__codelineno-58-2" href="#__codelineno-58-2"></a>http://localhost:8025
</span><span id="__span-58-3"><a id="__codelineno-58-3" name="__codelineno-58-3" href="#__codelineno-58-3"></a>
</span><span id="__span-58-4"><a id="__codelineno-58-4" name="__codelineno-58-4" href="#__codelineno-58-4"></a><span class="c1"># All emails appear here instead of being sent</span>
</span></code></pre></div>
<p><strong>Solution 4: Test SMTP connection</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-59-1"><a id="__codelineno-59-1" name="__codelineno-59-1" href="#__codelineno-59-1"></a><span class="c1"># Test SMTP via API</span>
</span><span id="__span-59-2"><a id="__codelineno-59-2" name="__codelineno-59-2" href="#__codelineno-59-2"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://localhost:4000/api/test-email<span class="w"> </span><span class="se">\</span>
</span><span id="__span-59-3"><a id="__codelineno-59-3" name="__codelineno-59-3" href="#__codelineno-59-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-59-4"><a id="__codelineno-59-4" name="__codelineno-59-4" href="#__codelineno-59-4"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Authorization: Bearer YOUR_TOKEN&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-59-5"><a id="__codelineno-59-5" name="__codelineno-59-5" href="#__codelineno-59-5"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{</span>
</span><span id="__span-59-6"><a id="__codelineno-59-6" name="__codelineno-59-6" href="#__codelineno-59-6"></a><span class="s1"> &quot;to&quot;: &quot;test@example.com&quot;,</span>
</span><span id="__span-59-7"><a id="__codelineno-59-7" name="__codelineno-59-7" href="#__codelineno-59-7"></a><span class="s1"> &quot;subject&quot;: &quot;Test&quot;,</span>
</span><span id="__span-59-8"><a id="__codelineno-59-8" name="__codelineno-59-8" href="#__codelineno-59-8"></a><span class="s1"> &quot;text&quot;: &quot;Test email&quot;</span>
</span><span id="__span-59-9"><a id="__codelineno-59-9" name="__codelineno-59-9" href="#__codelineno-59-9"></a><span class="s1"> }&#39;</span>
</span></code></pre></div>
<p><strong>Solution 5: Manually reset password</strong></p>
<p>See "Manually reset password" in previous section.</p>
<h4 id="prevention_12">Prevention<a class="headerlink" href="#prevention_12" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Email testing</strong> - Test email delivery in production</li>
<li><strong>Clear from address</strong> - Use recognizable sender</li>
<li><strong>SPF/DKIM/DMARC</strong> - Configure email authentication</li>
<li><strong>Resend option</strong> - Easy way to resend email</li>
</ul>
<hr />
<h2 id="rate-limiting">Rate Limiting<a class="headerlink" href="#rate-limiting" title="Permanent link">&para;</a></h2>
<h3 id="too-many-login-attempts">Too Many Login Attempts<a class="headerlink" href="#too-many-login-attempts" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟡 Medium</p>
<h4 id="symptoms_13">Symptoms<a class="headerlink" href="#symptoms_13" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-60-1"><a id="__codelineno-60-1" name="__codelineno-60-1" href="#__codelineno-60-1"></a><span class="p">{</span>
</span><span id="__span-60-2"><a id="__codelineno-60-2" name="__codelineno-60-2" href="#__codelineno-60-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Too Many Requests&quot;</span><span class="p">,</span>
</span><span id="__span-60-3"><a id="__codelineno-60-3" name="__codelineno-60-3" href="#__codelineno-60-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Too many login attempts. Please try again later.&quot;</span>
</span><span id="__span-60-4"><a id="__codelineno-60-4" name="__codelineno-60-4" href="#__codelineno-60-4"></a><span class="p">}</span>
</span></code></pre></div>
<h4 id="common-causes_11">Common Causes<a class="headerlink" href="#common-causes_11" title="Permanent link">&para;</a></h4>
<ol>
<li><strong>Too many failed logins</strong> - More than 10/minute</li>
<li><strong>Automated attack</strong> - Bot trying to brute-force</li>
<li><strong>Shared IP</strong> - Multiple users behind same NAT</li>
</ol>
<h4 id="solutions_13">Solutions<a class="headerlink" href="#solutions_13" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Wait and retry</strong></p>
<p>Rate limit is per IP address:
- <strong>Limit:</strong> 10 requests per minute
- <strong>Window:</strong> 1 minute
- <strong>Action:</strong> Wait 1 minute, then try again</p>
<p><strong>Solution 2: Check Redis rate limit</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-61-1"><a id="__codelineno-61-1" name="__codelineno-61-1" href="#__codelineno-61-1"></a><span class="c1"># Connect to Redis</span>
</span><span id="__span-61-2"><a id="__codelineno-61-2" name="__codelineno-61-2" href="#__codelineno-61-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>redis<span class="w"> </span>redis-cli<span class="w"> </span>-a<span class="w"> </span>YOUR_REDIS_PASSWORD
</span><span id="__span-61-3"><a id="__codelineno-61-3" name="__codelineno-61-3" href="#__codelineno-61-3"></a>
</span><span id="__span-61-4"><a id="__codelineno-61-4" name="__codelineno-61-4" href="#__codelineno-61-4"></a><span class="c1"># Find rate limit keys</span>
</span><span id="__span-61-5"><a id="__codelineno-61-5" name="__codelineno-61-5" href="#__codelineno-61-5"></a>KEYS<span class="w"> </span>rl:auth:*
</span><span id="__span-61-6"><a id="__codelineno-61-6" name="__codelineno-61-6" href="#__codelineno-61-6"></a>
</span><span id="__span-61-7"><a id="__codelineno-61-7" name="__codelineno-61-7" href="#__codelineno-61-7"></a><span class="c1"># Check specific IP</span>
</span><span id="__span-61-8"><a id="__codelineno-61-8" name="__codelineno-61-8" href="#__codelineno-61-8"></a>GET<span class="w"> </span>rl:auth:192.168.1.100
</span><span id="__span-61-9"><a id="__codelineno-61-9" name="__codelineno-61-9" href="#__codelineno-61-9"></a>
</span><span id="__span-61-10"><a id="__codelineno-61-10" name="__codelineno-61-10" href="#__codelineno-61-10"></a><span class="c1"># Shows number of requests in current window</span>
</span></code></pre></div>
<p><strong>Solution 3: Clear rate limit (admin)</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-62-1"><a id="__codelineno-62-1" name="__codelineno-62-1" href="#__codelineno-62-1"></a><span class="c1"># Delete rate limit key for IP</span>
</span><span id="__span-62-2"><a id="__codelineno-62-2" name="__codelineno-62-2" href="#__codelineno-62-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>redis<span class="w"> </span>redis-cli<span class="w"> </span>-a<span class="w"> </span>YOUR_REDIS_PASSWORD<span class="w"> </span>DEL<span class="w"> </span>rl:auth:192.168.1.100
</span><span id="__span-62-3"><a id="__codelineno-62-3" name="__codelineno-62-3" href="#__codelineno-62-3"></a>
</span><span id="__span-62-4"><a id="__codelineno-62-4" name="__codelineno-62-4" href="#__codelineno-62-4"></a><span class="c1"># Or clear all auth rate limits</span>
</span><span id="__span-62-5"><a id="__codelineno-62-5" name="__codelineno-62-5" href="#__codelineno-62-5"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>redis<span class="w"> </span>redis-cli<span class="w"> </span>-a<span class="w"> </span>YOUR_REDIS_PASSWORD<span class="w"> </span>--scan<span class="w"> </span>--pattern<span class="w"> </span><span class="s2">&quot;rl:auth:*&quot;</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>xargs<span class="w"> </span>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>redis<span class="w"> </span>redis-cli<span class="w"> </span>-a<span class="w"> </span>YOUR_REDIS_PASSWORD<span class="w"> </span>DEL
</span></code></pre></div>
<p><strong>Solution 4: Adjust rate limit</strong></p>
<p>In <code>api/src/middleware/rate-limit.ts</code>:</p>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-63-1"><a id="__codelineno-63-1" name="__codelineno-63-1" href="#__codelineno-63-1"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">authRateLimit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">rateLimit</span><span class="p">({</span>
</span><span id="__span-63-2"><a id="__codelineno-63-2" name="__codelineno-63-2" href="#__codelineno-63-2"></a><span class="w"> </span><span class="nx">windowMs</span><span class="o">:</span><span class="w"> </span><span class="kt">60</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1000</span><span class="p">,</span><span class="w"> </span><span class="c1">// 1 minute</span>
</span><span id="__span-63-3"><a id="__codelineno-63-3" name="__codelineno-63-3" href="#__codelineno-63-3"></a><span class="w"> </span><span class="nx">max</span><span class="o">:</span><span class="w"> </span><span class="kt">10</span><span class="p">,</span><span class="w"> </span><span class="c1">// 10 requests per minute</span>
</span><span id="__span-63-4"><a id="__codelineno-63-4" name="__codelineno-63-4" href="#__codelineno-63-4"></a><span class="w"> </span><span class="nx">message</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Too many login attempts. Please try again later.&#39;</span><span class="p">,</span>
</span><span id="__span-63-5"><a id="__codelineno-63-5" name="__codelineno-63-5" href="#__codelineno-63-5"></a><span class="w"> </span><span class="nx">standardHeaders</span><span class="o">:</span><span class="w"> </span><span class="kt">true</span><span class="p">,</span>
</span><span id="__span-63-6"><a id="__codelineno-63-6" name="__codelineno-63-6" href="#__codelineno-63-6"></a><span class="w"> </span><span class="nx">legacyHeaders</span><span class="o">:</span><span class="w"> </span><span class="kt">false</span><span class="p">,</span>
</span><span id="__span-63-7"><a id="__codelineno-63-7" name="__codelineno-63-7" href="#__codelineno-63-7"></a><span class="p">});</span>
</span><span id="__span-63-8"><a id="__codelineno-63-8" name="__codelineno-63-8" href="#__codelineno-63-8"></a>
</span><span id="__span-63-9"><a id="__codelineno-63-9" name="__codelineno-63-9" href="#__codelineno-63-9"></a><span class="c1">// Increase to 20/minute:</span>
</span><span id="__span-63-10"><a id="__codelineno-63-10" name="__codelineno-63-10" href="#__codelineno-63-10"></a><span class="nx">max</span><span class="o">:</span><span class="w"> </span><span class="kt">20</span><span class="p">,</span>
</span></code></pre></div>
<p><strong>Solution 5: Use different IP</strong></p>
<p>If behind NAT with many users:
1. Use VPN
2. Use mobile network
3. Contact administrator to whitelist IP</p>
<h4 id="prevention_13">Prevention<a class="headerlink" href="#prevention_13" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Reasonable limits</strong> - 10/min is reasonable</li>
<li><strong>Per-account limit</strong> - Also limit by email (not just IP)</li>
<li><strong>CAPTCHA</strong> - Add CAPTCHA after 3 failed attempts</li>
<li><strong>Account lockout</strong> - Lock account after 10 failed attempts</li>
</ul>
<hr />
<h3 id="account-temporarily-locked">Account Temporarily Locked<a class="headerlink" href="#account-temporarily-locked" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟡 Medium</p>
<h4 id="symptoms_14">Symptoms<a class="headerlink" href="#symptoms_14" title="Permanent link">&para;</a></h4>
<div class="language-json highlight"><pre><span></span><code><span id="__span-64-1"><a id="__codelineno-64-1" name="__codelineno-64-1" href="#__codelineno-64-1"></a><span class="p">{</span>
</span><span id="__span-64-2"><a id="__codelineno-64-2" name="__codelineno-64-2" href="#__codelineno-64-2"></a><span class="w"> </span><span class="nt">&quot;error&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Forbidden&quot;</span><span class="p">,</span>
</span><span id="__span-64-3"><a id="__codelineno-64-3" name="__codelineno-64-3" href="#__codelineno-64-3"></a><span class="w"> </span><span class="nt">&quot;message&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Account temporarily locked due to too many failed login attempts. Please try again in 30 minutes.&quot;</span>
</span><span id="__span-64-4"><a id="__codelineno-64-4" name="__codelineno-64-4" href="#__codelineno-64-4"></a><span class="p">}</span>
</span></code></pre></div>
<h4 id="solutions_14">Solutions<a class="headerlink" href="#solutions_14" title="Permanent link">&para;</a></h4>
<p><strong>Solution 1: Wait for unlock</strong></p>
<p>Accounts auto-unlock after lockout period (default: 30 minutes).</p>
<p><strong>Solution 2: Manually unlock (admin)</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-65-1"><a id="__codelineno-65-1" name="__codelineno-65-1" href="#__codelineno-65-1"></a><span class="c1"># If lockout implemented in database:</span>
</span><span id="__span-65-2"><a id="__codelineno-65-2" name="__codelineno-65-2" href="#__codelineno-65-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-65-3"><a id="__codelineno-65-3" name="__codelineno-65-3" href="#__codelineno-65-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE \&quot;User\&quot; SET \&quot;lockedUntil\&quot; = NULL WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span></code></pre></div>
<p><strong>Solution 3: Contact administrator</strong></p>
<p>If you're a user:
1. Contact system administrator
2. Verify your identity
3. Request account unlock</p>
<h4 id="prevention_14">Prevention<a class="headerlink" href="#prevention_14" title="Permanent link">&para;</a></h4>
<ul>
<li><strong>Reasonable threshold</strong> - 10 failed attempts is reasonable</li>
<li><strong>Automatic unlock</strong> - Auto-unlock after time period</li>
<li><strong>Email notification</strong> - Notify user of lockout</li>
<li><strong>Appeal process</strong> - Way to appeal false positive</li>
</ul>
<div class="admonition note">
<p class="admonition-title">V2 Status</p>
<p>V2 doesn't currently have account lockout. This section is for future implementation.</p>
</div>
<hr />
<h2 id="debugging-auth">Debugging Auth<a class="headerlink" href="#debugging-auth" title="Permanent link">&para;</a></h2>
<h3 id="checking-jwt-payload">Checking JWT Payload<a class="headerlink" href="#checking-jwt-payload" title="Permanent link">&para;</a></h3>
<p><strong>Severity:</strong> 🟢 Low (informational)</p>
<h4 id="how-to-decode-jwt">How to Decode JWT<a class="headerlink" href="#how-to-decode-jwt" title="Permanent link">&para;</a></h4>
<div class="language-javascript highlight"><pre><span></span><code><span id="__span-66-1"><a id="__codelineno-66-1" name="__codelineno-66-1" href="#__codelineno-66-1"></a><span class="c1">// In browser console</span>
</span><span id="__span-66-2"><a id="__codelineno-66-2" name="__codelineno-66-2" href="#__codelineno-66-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">token</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEyMyIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsInJvbGUiOiJVU0VSIiwiaWF0IjoxNzA4MDAwMDAwLCJleHAiOjE3MDgwMDA5MDB9.signature&#39;</span><span class="p">;</span>
</span><span id="__span-66-3"><a id="__codelineno-66-3" name="__codelineno-66-3" href="#__codelineno-66-3"></a>
</span><span id="__span-66-4"><a id="__codelineno-66-4" name="__codelineno-66-4" href="#__codelineno-66-4"></a><span class="c1">// Decode header</span>
</span><span id="__span-66-5"><a id="__codelineno-66-5" name="__codelineno-66-5" href="#__codelineno-66-5"></a><span class="kd">const</span><span class="w"> </span><span class="nx">header</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">atob</span><span class="p">(</span><span class="nx">token</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)[</span><span class="mf">0</span><span class="p">]));</span>
</span><span id="__span-66-6"><a id="__codelineno-66-6" name="__codelineno-66-6" href="#__codelineno-66-6"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Header:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">header</span><span class="p">);</span>
</span><span id="__span-66-7"><a id="__codelineno-66-7" name="__codelineno-66-7" href="#__codelineno-66-7"></a><span class="c1">// { alg: &#39;HS256&#39;, typ: &#39;JWT&#39; }</span>
</span><span id="__span-66-8"><a id="__codelineno-66-8" name="__codelineno-66-8" href="#__codelineno-66-8"></a>
</span><span id="__span-66-9"><a id="__codelineno-66-9" name="__codelineno-66-9" href="#__codelineno-66-9"></a><span class="c1">// Decode payload</span>
</span><span id="__span-66-10"><a id="__codelineno-66-10" name="__codelineno-66-10" href="#__codelineno-66-10"></a><span class="kd">const</span><span class="w"> </span><span class="nx">payload</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">atob</span><span class="p">(</span><span class="nx">token</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)[</span><span class="mf">1</span><span class="p">]));</span>
</span><span id="__span-66-11"><a id="__codelineno-66-11" name="__codelineno-66-11" href="#__codelineno-66-11"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Payload:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">payload</span><span class="p">);</span>
</span><span id="__span-66-12"><a id="__codelineno-66-12" name="__codelineno-66-12" href="#__codelineno-66-12"></a><span class="c1">// {</span>
</span><span id="__span-66-13"><a id="__codelineno-66-13" name="__codelineno-66-13" href="#__codelineno-66-13"></a><span class="c1">// id: &#39;123&#39;,</span>
</span><span id="__span-66-14"><a id="__codelineno-66-14" name="__codelineno-66-14" href="#__codelineno-66-14"></a><span class="c1">// email: &#39;test@example.com&#39;,</span>
</span><span id="__span-66-15"><a id="__codelineno-66-15" name="__codelineno-66-15" href="#__codelineno-66-15"></a><span class="c1">// role: &#39;USER&#39;,</span>
</span><span id="__span-66-16"><a id="__codelineno-66-16" name="__codelineno-66-16" href="#__codelineno-66-16"></a><span class="c1">// iat: 1708000000, // Issued at (Unix timestamp)</span>
</span><span id="__span-66-17"><a id="__codelineno-66-17" name="__codelineno-66-17" href="#__codelineno-66-17"></a><span class="c1">// exp: 1708000900 // Expires at (Unix timestamp)</span>
</span><span id="__span-66-18"><a id="__codelineno-66-18" name="__codelineno-66-18" href="#__codelineno-66-18"></a><span class="c1">// }</span>
</span><span id="__span-66-19"><a id="__codelineno-66-19" name="__codelineno-66-19" href="#__codelineno-66-19"></a>
</span><span id="__span-66-20"><a id="__codelineno-66-20" name="__codelineno-66-20" href="#__codelineno-66-20"></a><span class="c1">// Check expiration</span>
</span><span id="__span-66-21"><a id="__codelineno-66-21" name="__codelineno-66-21" href="#__codelineno-66-21"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Issued:&#39;</span><span class="p">,</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(</span><span class="nx">payload</span><span class="p">.</span><span class="nx">iat</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1000</span><span class="p">));</span>
</span><span id="__span-66-22"><a id="__codelineno-66-22" name="__codelineno-66-22" href="#__codelineno-66-22"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Expires:&#39;</span><span class="p">,</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(</span><span class="nx">payload</span><span class="p">.</span><span class="nx">exp</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1000</span><span class="p">));</span>
</span><span id="__span-66-23"><a id="__codelineno-66-23" name="__codelineno-66-23" href="#__codelineno-66-23"></a><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Is expired:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="nx">payload</span><span class="p">.</span><span class="nx">exp</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1000</span><span class="p">);</span>
</span></code></pre></div>
<hr />
<h3 id="verifying-refresh-tokens">Verifying Refresh Tokens<a class="headerlink" href="#verifying-refresh-tokens" title="Permanent link">&para;</a></h3>
<h4 id="check-refresh-token-in-database">Check Refresh Token in Database<a class="headerlink" href="#check-refresh-token-in-database" title="Permanent link">&para;</a></h4>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-67-1"><a id="__codelineno-67-1" name="__codelineno-67-1" href="#__codelineno-67-1"></a><span class="c1"># Find all refresh tokens for user</span>
</span><span id="__span-67-2"><a id="__codelineno-67-2" name="__codelineno-67-2" href="#__codelineno-67-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-67-3"><a id="__codelineno-67-3" name="__codelineno-67-3" href="#__codelineno-67-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT rt.id, rt.\&quot;createdAt\&quot;, rt.\&quot;expiresAt\&quot;, u.email</span>
</span><span id="__span-67-4"><a id="__codelineno-67-4" name="__codelineno-67-4" href="#__codelineno-67-4"></a><span class="s2"> FROM \&quot;RefreshToken\&quot; rt</span>
</span><span id="__span-67-5"><a id="__codelineno-67-5" name="__codelineno-67-5" href="#__codelineno-67-5"></a><span class="s2"> JOIN \&quot;User\&quot; u ON rt.\&quot;userId\&quot; = u.id</span>
</span><span id="__span-67-6"><a id="__codelineno-67-6" name="__codelineno-67-6" href="#__codelineno-67-6"></a><span class="s2"> WHERE u.email = &#39;user@example.com&#39;</span>
</span><span id="__span-67-7"><a id="__codelineno-67-7" name="__codelineno-67-7" href="#__codelineno-67-7"></a><span class="s2"> ORDER BY rt.\&quot;createdAt\&quot; DESC;&quot;</span>
</span><span id="__span-67-8"><a id="__codelineno-67-8" name="__codelineno-67-8" href="#__codelineno-67-8"></a>
</span><span id="__span-67-9"><a id="__codelineno-67-9" name="__codelineno-67-9" href="#__codelineno-67-9"></a><span class="c1"># Output:</span>
</span><span id="__span-67-10"><a id="__codelineno-67-10" name="__codelineno-67-10" href="#__codelineno-67-10"></a><span class="c1"># id | createdAt | expiresAt | email</span>
</span><span id="__span-67-11"><a id="__codelineno-67-11" name="__codelineno-67-11" href="#__codelineno-67-11"></a><span class="c1"># uuid-here | 2026-02-10 10:00:00 | 2026-02-17 10:00:00 | user@example.com</span>
</span><span id="__span-67-12"><a id="__codelineno-67-12" name="__codelineno-67-12" href="#__codelineno-67-12"></a>
</span><span id="__span-67-13"><a id="__codelineno-67-13" name="__codelineno-67-13" href="#__codelineno-67-13"></a><span class="c1"># Check if expired:</span>
</span><span id="__span-67-14"><a id="__codelineno-67-14" name="__codelineno-67-14" href="#__codelineno-67-14"></a><span class="c1"># SELECT id FROM &quot;RefreshToken&quot; WHERE id = &#39;uuid&#39; AND &quot;expiresAt&quot; &gt; NOW();</span>
</span></code></pre></div>
<hr />
<h3 id="checking-user-status">Checking User Status<a class="headerlink" href="#checking-user-status" title="Permanent link">&para;</a></h3>
<h4 id="view-user-details">View User Details<a class="headerlink" href="#view-user-details" title="Permanent link">&para;</a></h4>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-68-1"><a id="__codelineno-68-1" name="__codelineno-68-1" href="#__codelineno-68-1"></a><span class="c1"># Full user details</span>
</span><span id="__span-68-2"><a id="__codelineno-68-2" name="__codelineno-68-2" href="#__codelineno-68-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-68-3"><a id="__codelineno-68-3" name="__codelineno-68-3" href="#__codelineno-68-3"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT id, email, name, role, \&quot;createdAt\&quot;, \&quot;updatedAt\&quot;</span>
</span><span id="__span-68-4"><a id="__codelineno-68-4" name="__codelineno-68-4" href="#__codelineno-68-4"></a><span class="s2"> FROM \&quot;User\&quot;</span>
</span><span id="__span-68-5"><a id="__codelineno-68-5" name="__codelineno-68-5" href="#__codelineno-68-5"></a><span class="s2"> WHERE email = &#39;user@example.com&#39;;&quot;</span>
</span><span id="__span-68-6"><a id="__codelineno-68-6" name="__codelineno-68-6" href="#__codelineno-68-6"></a>
</span><span id="__span-68-7"><a id="__codelineno-68-7" name="__codelineno-68-7" href="#__codelineno-68-7"></a><span class="c1"># Check active sessions</span>
</span><span id="__span-68-8"><a id="__codelineno-68-8" name="__codelineno-68-8" href="#__codelineno-68-8"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>changemaker_v2<span class="w"> </span><span class="se">\</span>
</span><span id="__span-68-9"><a id="__codelineno-68-9" name="__codelineno-68-9" href="#__codelineno-68-9"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT COUNT(*) as active_sessions</span>
</span><span id="__span-68-10"><a id="__codelineno-68-10" name="__codelineno-68-10" href="#__codelineno-68-10"></a><span class="s2"> FROM \&quot;RefreshToken\&quot; rt</span>
</span><span id="__span-68-11"><a id="__codelineno-68-11" name="__codelineno-68-11" href="#__codelineno-68-11"></a><span class="s2"> JOIN \&quot;User\&quot; u ON rt.\&quot;userId\&quot; = u.id</span>
</span><span id="__span-68-12"><a id="__codelineno-68-12" name="__codelineno-68-12" href="#__codelineno-68-12"></a><span class="s2"> WHERE u.email = &#39;user@example.com&#39;</span>
</span><span id="__span-68-13"><a id="__codelineno-68-13" name="__codelineno-68-13" href="#__codelineno-68-13"></a><span class="s2"> AND rt.\&quot;expiresAt\&quot; &gt; NOW();&quot;</span>
</span></code></pre></div>
<hr />
<h2 id="related-documentation">Related Documentation<a class="headerlink" href="#related-documentation" title="Permanent link">&para;</a></h2>
<h3 id="authentication-documentation">Authentication Documentation<a class="headerlink" href="#authentication-documentation" title="Permanent link">&para;</a></h3>
<ul>
<li><a href="./">Auth Issues</a> - This guide</li>
<li><a href="../technical/api-reference.md#authentication">API Reference</a> - Auth endpoints</li>
<li><a href="../../../SECURITY_AUDIT_2025-02-11.md">Security Audit</a> - Security improvements</li>
</ul>
<h3 id="other-troubleshooting">Other Troubleshooting<a class="headerlink" href="#other-troubleshooting" title="Permanent link">&para;</a></h3>
<ul>
<li><a href="../common-errors/">Common Errors</a> - General errors</li>
<li><a href="../database-issues/">Database Issues</a> - Database problems</li>
<li><a href="../email-issues/">Email Issues</a> - Email and password reset</li>
</ul>
<h3 id="security-resources">Security Resources<a class="headerlink" href="#security-resources" title="Permanent link">&para;</a></h3>
<ul>
<li><a href="https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html">OWASP Authentication Cheat Sheet</a></li>
<li><a href="https://tools.ietf.org/html/rfc8725">JWT Best Practices</a></li>
<li><a href="https://github.com/kelektiv/node.bcrypt.js">bcrypt</a></li>
</ul>
<hr />
<p><strong>Last Updated:</strong> February 2026
<strong>Version:</strong> V2.0
<strong>Status:</strong> Complete</p>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../common-errors/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Common Errors">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Previous
</span>
<div class="md-ellipsis">
Common Errors
</div>
</div>
</a>
<a href="../database-issues/" class="md-footer__link md-footer__link--next" aria-label="Next: Database Issues">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Database Issues
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2024 The Bunker Operations <a href="#__consent">Change cookie settings</a>
</div>
</div>
<div class="md-social">
<a href="https://gitea.bnkops.com/admin" target="_blank" rel="noopener" title="Gitea Repository" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
</a>
<a href="https://listmonk.bnkops.com/subscription/form" target="_blank" rel="noopener" title="Newsletter" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M536.4-26.3c9.8-3.5 20.6-1 28 6.3s9.8 18.2 6.3 28l-178 496.9c-5 13.9-18.1 23.1-32.8 23.1-14.2 0-27-8.6-32.3-21.7l-64.2-158c-4.5-11-2.5-23.6 5.2-32.6l94.5-112.4c5.1-6.1 4.7-15-.9-20.6s-14.6-6-20.6-.9l-112.4 94.3c-9.1 7.6-21.6 9.6-32.6 5.2L38.1 216.8c-13.1-5.3-21.7-18.1-21.7-32.3 0-14.7 9.2-27.8 23.1-32.8z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../../..", "features": ["announce.dismiss", "content.action.edit", "content.action.view", "content.code.annotate", "content.code.copy", "content.tooltips", "navigation.expand", "navigation.footer", "navigation.indexes", "navigation.path", "navigation.prune", "navigation.sections", "navigation.tabs", "navigation.tabs.sticky", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../../assets/javascripts/bundle.79ae519e.min.js"></script>
<script src="../../../javascripts/home.js"></script>
<script src="../../../javascripts/github-widget.js"></script>
<script src="../../../javascripts/gitea-widget.js"></script>
<script src="../../../assets/js/env-config.js"></script>
<script src="../../../assets/js/video-player.js"></script>
</body>
</html>