A small, easy-to-read example of token-based authentication built with Flask and Flask-RESTful. It shows how to register users, log them in, issue short-lived access tokens and longer-lived refresh tokens, and protect routes by user role (user / admin / super admin).
It is intentionally minimal so you can read the whole thing in an afternoon and use it as a starting point for your own API.
- ๐ Register / Login / Logout with JSON requests
- ๐ช JWT-style access + refresh tokens (signed and time-limited)
- ๐ฎ Role-based access โ
user,admin,super_admin - ๐ Passwords hashed with bcrypt (never stored in plaintext)
- ๐งช A small test suite you can run in one command
- ๐๏ธ SQLite database (zero setup) via Flask-SQLAlchemy
| Purpose | Library |
|---|---|
| Web framework | Flask + Flask-RESTful |
| Database / ORM | Flask-SQLAlchemy + SQLite |
| Password hashing | bcrypt |
| Token signing | itsdangerous |
| Auth header parsing | Flask-HTTPAuth |
flask-restful-login/
โโโ main.py # App entry point (creates and runs the app)
โโโ requirements.txt
โโโ api/
โโโ conf/
โ โโโ auth.py # Token serializers + auth object
โ โโโ routes.py # URL โ handler wiring
โโโ handlers/
โ โโโ UserHandlers.py # Register, Login, Logout, Refresh, etc.
โโโ models/
โ โโโ models.py # User + Blacklist models, password hashing
โโโ tests/ # Unit tests
- Python 3.8+
- A tool to send HTTP requests. Any of these work:
httpie (used below),
curl, Postman, or Insomnia.
# 1. Get the code
git clone https://github.com/melihcolpan/flask-restful-login
cd flask-restful-login
# 2. Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# 3. Install dependencies
pip install -r requirements.txt
# 4. Set the required secrets (see the table below).
# These can be any random strings โ here we generate them automatically.
export JWT_SECRET=$(python -c "import secrets; print(secrets.token_hex(32))")
export REFRESH_JWT_SECRET=$(python -c "import secrets; print(secrets.token_hex(32))")
export SECRET_KEY=$(python -c "import secrets; print(secrets.token_hex(32))")
# 5. Run it
python main.pyThe API is now running at http://localhost:5000.
๐ก On Windows PowerShell, set a variable with
$env:JWT_SECRET="..."instead ofexport.
| Variable | Required | Default | What it does |
|---|---|---|---|
JWT_SECRET |
โ | โ | Signs access tokens. Keep it secret. |
REFRESH_JWT_SECRET |
โ | โ | Signs refresh tokens. Keep it secret. |
SECRET_KEY |
โ | โ | Flask's secret key (sessions / security). |
DEBUG |
โ | False |
Set to True for the auto-reloading debug server. |
The app refuses to start if a required secret is missing โ this is on purpose, so you never accidentally ship hardcoded secrets to production.
- You register a user, then log in with their email + password.
- The server returns two tokens:
access_tokenโ short-lived (1 hour). Send it on every protected request in the headerAuthorization: Bearer <access_token>.refresh_tokenโ longer-lived (2 hours). Use it to get a new access token when the old one expires, without logging in again.
- Logout invalidates a refresh token by adding it to a blacklist.
Base URL: http://localhost:5000
| Method | Endpoint | Auth required | Description |
|---|---|---|---|
| GET | / |
โ | Health check / hello message |
| POST | /v1/auth/register |
โ | Create a new user |
| POST | /v1/auth/login |
โ | Log in, receive tokens |
| POST | /v1/auth/refresh |
โ | Exchange a refresh token for a new access token |
| POST | /v1/auth/logout |
โ Bearer | Invalidate a refresh token |
| POST | /v1/auth/password_reset |
โ Bearer | Change your password |
| GET | /data_user |
โ Bearer | Example route for any logged-in user |
| GET | /data_admin |
โ Admin | Example route for admins |
| GET | /data_super_admin |
โ Super admin | Example route for super admins |
| GET | /users |
โ Super admin | Search users by name/email/date |
Note on roles:
registeralways creates a normaluser. Theadminandsuper_adminroles are assigned out-of-band (e.g. directly in the database) โ there are intentionally no default admin accounts.
The examples use httpie. A curl equivalent is shown for
the first two so you can adapt the rest.
http POST :5000/v1/auth/register \
username=alice password=s3cret email=alice@example.com# curl version
curl -X POST http://localhost:5000/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"alice","password":"s3cret","email":"alice@example.com"}'Response:
{ "status": "registration completed." }http POST :5000/v1/auth/login email=alice@example.com password=s3cret# curl version
curl -X POST http://localhost:5000/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com","password":"s3cret"}'Response โ copy the access_token, you'll need it next:
{
"access_token": "eyJ...",
"refresh_token": "eyJ..."
}Pass the access token in the Authorization header:
http GET :5000/data_user Authorization:"Bearer <ACCESS_TOKEN>"http POST :5000/v1/auth/refresh refresh_token=<REFRESH_TOKEN>http POST :5000/v1/auth/password_reset \
Authorization:"Bearer <ACCESS_TOKEN>" \
old_pass=s3cret new_pass=ev3nm0resecrethttp POST :5000/v1/auth/logout \
Authorization:"Bearer <ACCESS_TOKEN>" \
refresh_token=<REFRESH_TOKEN>http GET :5000/users \
Authorization:"Bearer <ACCESS_TOKEN>" \
usernames==alice,bob \
emails==alice@example.com,bob@example.com \
start_date==01.01.1990 end_date==01.01.2050# Tests still need the secret env vars to import the app.
export JWT_SECRET=test REFRESH_JWT_SECRET=test SECRET_KEY=test
python -m unittest discover -s api/tests -p "tests_*.py"You should see all tests pass.
This example follows a few basic good practices you should keep in your own apps:
- No hardcoded secrets โ token secrets and
SECRET_KEYcome from the environment, and the app won't start without them. - Passwords are hashed with bcrypt โ the database never stores plaintext.
- No default accounts โ there are no built-in admin users with known passwords.
- Login doesn't leak which emails exist โ a wrong password and an unknown user return the same error.
For real production use you'd also want HTTPS, a production WSGI server (e.g. gunicorn), a real database (PostgreSQL), and rate limiting.
MIT โ free to use, modify, and learn from.