33import bcrypt
44import jwt
55
6+ from datetime import datetime , timezone , timedelta
7+
68from dataclasses import dataclass , field
79from typing import Optional
810from asyncpg import Connection
@@ -86,14 +88,26 @@ async def authenticate(
8688 if not session :
8789 raise ValueError ("Something went wrong creating the session" )
8890
91+ # Calculate expiration times
92+ access_token_exp = datetime .now (timezone .utc ) + timedelta (minutes = self .settings .app .ACCESS_TOKEN_EXPIRE_MINUTES )
93+ refresh_token_exp = datetime .now (timezone .utc ) + timedelta (days = self .settings .app .REFRESH_TOKEN_EXPIRE_DAYS )
94+
8995 access_token_jwt = jwt .encode (
90- {"uuid" : str (user_uuid ), "access_token" : random_access_token },
96+ {
97+ "uuid" : str (user_uuid ),
98+ "access_token" : random_access_token ,
99+ "exp" : access_token_exp
100+ },
91101 key = self .settings .app .SECRET_KEY ,
92102 algorithm = self .settings .app .JWT_ALGORITHM ,
93103 )
94104
95105 refresh_token_jwt = jwt .encode (
96- {"uuid" : str (user_uuid ), "refresh_token" : random_refresh_token },
106+ {
107+ "uuid" : str (user_uuid ),
108+ "refresh_token" : random_refresh_token ,
109+ "exp" : refresh_token_exp
110+ },
97111 key = self .settings .app .SECRET_KEY ,
98112 algorithm = self .settings .app .JWT_ALGORITHM ,
99113 )
@@ -105,7 +119,6 @@ async def refresh_access_token(
105119 ) -> Token :
106120 """Refreshes the access_token using a valid refresh_token"""
107121 try :
108- # Decode the refresh token JWT
109122 decoded = jwt .decode (
110123 jwt = refresh_token ,
111124 key = self .settings .app .SECRET_KEY ,
@@ -146,18 +159,29 @@ async def refresh_access_token(
146159 # Update only the access token in the existing session
147160 await self .session_repository .update_access_token (
148161 session_uuid = session ["uuid" ],
149- access_token = access_token_hash .hex ()
162+ access_token = access_token_hash .hex (),
163+ user_agent = user_agent ,
164+ ip = ip
150165 )
151166
167+ # Calculate expiration time for new access token
168+ access_token_exp = datetime .now (timezone .utc ) + timedelta (minutes = self .settings .app .ACCESS_TOKEN_EXPIRE_MINUTES )
169+
152170 # Generate new access token JWT
153171 access_token_jwt = jwt .encode (
154- {"uuid" : user_uuid , "access_token" : random_access_token },
172+ {
173+ "uuid" : user_uuid ,
174+ "access_token" : random_access_token ,
175+ "exp" : access_token_exp
176+ },
155177 key = self .settings .app .SECRET_KEY ,
156178 algorithm = self .settings .app .JWT_ALGORITHM ,
157179 )
158180
159181 # Return the new access token and keep the same refresh token
160182 return Token (access_token = access_token_jwt , refresh_token = refresh_token )
161183
184+ except jwt .ExpiredSignatureError :
185+ raise ValueError ("Refresh token expired" )
162186 except jwt .PyJWTError :
163187 raise ValueError ("Invalid refresh token format" )
0 commit comments