Day 4 of 5
⏱ ~60 minutes
Flask in 5 Days — Day 4

Authentication

User registration, login, and logout with Flask-Login. Password hashing with bcrypt. Protecting routes with @login_required.

Setting Up Flask-Login

Terminal
pip install flask-login flask-bcrypt
app.py
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_bcrypt import Bcrypt

bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'  # redirect here if not logged in

# User model must inherit UserMixin
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(128), nullable=False)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))
views.py — Register and Login
@app.route('/register', methods=['GET','POST'])
def register():
    if request.method == 'POST':
        hashed = bcrypt.generate_password_hash(request.form['password']).decode('utf-8')
        user = User(username=request.form['username'], password_hash=hashed)
        db.session.add(user)
        db.session.commit()
        return redirect(url_for('login'))
    return render_template('register.html')

@app.route('/login', methods=['GET','POST'])
def login():
    if request.method == 'POST':
        user = User.query.filter_by(username=request.form['username']).first()
        if user and bcrypt.check_password_hash(user.password_hash, request.form['password']):
            login_user(user, remember=True)
            return redirect(url_for('dashboard'))
        flash('Invalid credentials', 'danger')
    return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('index'))

@app.route('/dashboard')
@login_required
def dashboard():
    return render_template('dashboard.html', user=current_user)
📝 Day 4 Exercise
Add Auth to Your App
  1. I
  2. m
  3. p
  4. l
  5. e
  6. m
  7. e
  8. n
  9. t
  10. r
  11. e
  12. g
  13. i
  14. s
  15. t
  16. e
  17. r
  18. ,
  19. l
  20. o
  21. g
  22. i
  23. n
  24. ,
  25. a
  26. n
  27. d
  28. l
  29. o
  30. g
  31. o
  32. u
  33. t
  34. .
  35. H
  36. a
  37. s
  38. h
  39. p
  40. a
  41. s
  42. s
  43. w
  44. o
  45. r
  46. d
  47. s
  48. w
  49. i
  50. t
  51. h
  52. b
  53. c
  54. r
  55. y
  56. p
  57. t
  58. .
  59. P
  60. r
  61. o
  62. t
  63. e
  64. c
  65. t
  66. t
  67. h
  68. e
  69. d
  70. a
  71. s
  72. h
  73. b
  74. o
  75. a
  76. r
  77. d
  78. r
  79. o
  80. u
  81. t
  82. e
  83. w
  84. i
  85. t
  86. h
  87. @
  88. l
  89. o
  90. g
  91. i
  92. n
  93. _
  94. r
  95. e
  96. q
  97. u
  98. i
  99. r
  100. e
  101. d
  102. .
  103. S
  104. h
  105. o
  106. w
  107. t
  108. h
  109. e
  110. c
  111. u
  112. r
  113. r
  114. e
  115. n
  116. t
  117. u
  118. s
  119. e
  120. r
  121. '
  122. s
  123. u
  124. s
  125. e
  126. r
  127. n
  128. a
  129. m
  130. e
  131. i
  132. n
  133. t
  134. h
  135. e
  136. n
  137. a
  138. v
  139. .

Day 4 Summary

  • UserMixin adds is_authenticated, is_active, get_id() to your User model.
  • Always hash passwords. generate_password_hash(pw) → stored hash. check_password_hash(hash, pw) → True/False.
  • @login_required redirects unauthenticated users to login_manager.login_view.
  • current_user is available in all views and templates when Flask-Login is set up.
Finished this lesson?