@@ -50,6 +50,132 @@ dot.render('static/webapp_flow', format='png', cleanup=True)
50
50
51
51
The advantage of the PRG pattern is that it is very straightforward to implement and keeps most of the rendering logic on the server side. The disadvantage is that it requires an extra round trip to the database to fetch the updated data, and re-rendering the entire page template may be less efficient than a partial page update on the client side.
52
52
53
+ ### Authentication Flow
54
+
55
+ This application implements a comprehensive authentication system with security best practices. The diagrams below show the main authentication flows and security measures.
56
+
57
+ #### Registration and Login Flow
58
+
59
+ ``` {python}
60
+ #| echo: false
61
+ #| include: false
62
+ from graphviz import Digraph
63
+
64
+ # Create graph for registration/login
65
+ auth = Digraph(name='auth_flow')
66
+ auth.attr(rankdir='TB')
67
+ auth.attr('node', shape='box', style='rounded')
68
+
69
+ # Client-side nodes
70
+ with auth.subgraph(name='cluster_client') as client:
71
+ client.attr(label='Client')
72
+ client.node('register_form', 'Submit registration')
73
+ client.node('login_form', 'Submit login')
74
+ client.node('store_cookies', 'Store secure cookies')
75
+
76
+ # Server-side nodes
77
+ with auth.subgraph(name='cluster_server') as server:
78
+ server.attr(label='Server')
79
+ # Registration path
80
+ server.node('validate_register', 'Validate registration data')
81
+ server.node('hash_new', 'Hash new password')
82
+ server.node('store_user', 'Store user in database')
83
+
84
+ # Login path
85
+ server.node('validate_login', 'Validate login data')
86
+ server.node('verify_password', 'Verify password hash')
87
+ server.node('fetch_user', 'Fetch user from database')
88
+
89
+ # Common path
90
+ server.node('generate_tokens', 'Generate JWT tokens')
91
+
92
+ # Registration path
93
+ auth.edge('register_form', 'validate_register', 'POST /register')
94
+ auth.edge('validate_register', 'hash_new')
95
+ auth.edge('hash_new', 'store_user')
96
+ auth.edge('store_user', 'generate_tokens', 'Success')
97
+
98
+ # Login path
99
+ auth.edge('login_form', 'validate_login', 'POST /login')
100
+ auth.edge('validate_login', 'fetch_user')
101
+ auth.edge('fetch_user', 'verify_password')
102
+ auth.edge('verify_password', 'generate_tokens', 'Success')
103
+
104
+ # Common path
105
+ auth.edge('generate_tokens', 'store_cookies', 'Set-Cookie')
106
+
107
+ auth.render('static/auth_flow', format='png', cleanup=True)
108
+ ```
109
+
110
+ ![ Registration and Login Flow] ( static/auth_flow.png )
111
+
112
+ #### Password Reset Flow
113
+
114
+ ``` {python}
115
+ #| echo: false
116
+ #| include: false
117
+ from graphviz import Digraph
118
+
119
+ # Create graph for password reset
120
+ reset = Digraph(name='reset_flow')
121
+ reset.attr(rankdir='TB')
122
+ reset.attr('node', shape='box', style='rounded')
123
+
124
+ # Client-side nodes
125
+ reset.attr(label='Client')
126
+ reset.node('forgot', 'User submits forgot password form')
127
+ reset.node('reset', 'User submits reset password form')
128
+ reset.node('email_client', 'User clicks reset link')
129
+
130
+ # Server-side nodes
131
+ reset.attr(label='Server')
132
+ reset.node('validate', 'Validation')
133
+ reset.node('token_gen', 'Generate reset token')
134
+ reset.node('hash', 'Hash password')
135
+ reset.node('email_server', 'Send email with Resend')
136
+ reset.node('db', 'Database', shape='cylinder')
137
+
138
+ # Add edges with labels
139
+ reset.edge('forgot', 'token_gen', 'POST')
140
+ reset.edge('token_gen', 'db', 'Store')
141
+ reset.edge('token_gen', 'email_server', 'Add email/token as URL parameter')
142
+ reset.edge('email_server', 'email_client')
143
+ reset.edge('email_client', 'reset', 'Set email/token as form input')
144
+ reset.edge('reset', 'validate', 'POST')
145
+ reset.edge('validate', 'hash')
146
+ reset.edge('hash', 'db', 'Update')
147
+
148
+ reset.render('static/reset_flow', format='png', cleanup=True)
149
+ ```
150
+
151
+ ![ Password Reset Flow] ( static/reset_flow.png )
152
+
153
+ The authentication system implements multiple security measures:
154
+
155
+ 1 . ** Token Security** :
156
+ - JWT-based with separate access/refresh tokens
157
+ - Strict expiry times (30 min access, 30 day refresh)
158
+ - Token type validation
159
+ - HTTP-only cookies
160
+ - Secure flag enabled
161
+ - SameSite=strict restriction
162
+
163
+ 2 . ** Password Security** :
164
+ - Strong password requirements enforced
165
+ - Bcrypt hashing with random salt
166
+ - Password reset tokens are single-use
167
+ - Reset tokens have expiration
168
+
169
+ 3 . ** Cookie Security** :
170
+ - HTTP-only prevents JavaScript access
171
+ - Secure flag ensures HTTPS only
172
+ - Strict SameSite prevents CSRF
173
+
174
+ 4 . ** Error Handling** :
175
+ - Validation errors properly handled
176
+ - Security-related errors don't leak information
177
+ - Comprehensive error logging
178
+
53
179
### Install development dependencies in a VSCode Dev Container
54
180
55
181
If you use VSCode with Docker to develop in a container, the following VSCode Dev Container configuration will install all dependencies:
0 commit comments