@@ -33,6 +33,14 @@ def generate_token():
3333 return secrets .token_hex (nbytes = 32 )
3434
3535
36+ class PlaintextSecretAlreadyRead (Exception ):
37+ def __init__ (
38+ self ,
39+ message = "the secret you are trying to read is read-once and cannot be accessed directly again" ,
40+ ):
41+ super ().__init__ (message )
42+
43+
3644class ApiTokenManager (ControlOutboxProducingManager ):
3745 def create (self , * args , ** kwargs ):
3846 token_type : AuthTokenType | None = kwargs .get ("token_type" , None )
@@ -128,6 +136,8 @@ def _plaintext_token(self):
128136
129137 if plaintext_token is not None :
130138 setattr (self , f"_{ manager_class_name } __plaintext_token" , None )
139+ else :
140+ raise PlaintextSecretAlreadyRead ()
131141
132142 return plaintext_token
133143
@@ -144,9 +154,18 @@ def _plaintext_refresh_token(self):
144154 self , f"_{ manager_class_name } __plaintext_refresh_token" , None
145155 )
146156
147- if plaintext_refresh_token is not None :
157+ if plaintext_refresh_token :
148158 setattr (self , f"_{ manager_class_name } __plaintext_refresh_token" , None )
149159
160+ # some token types do not have refresh tokens, so we check to see
161+ # if there's a hash value that exists for the refresh token.
162+ #
163+ # if there is a hash value, then a refresh token is expected
164+ # and if the plaintext_refresh_token is None, then it has already
165+ # been read once so we should throw the exception
166+ if not plaintext_refresh_token and self .refresh_token :
167+ raise PlaintextSecretAlreadyRead ()
168+
150169 return plaintext_refresh_token
151170
152171 def save (self , * args : Any , ** kwargs : Any ) -> None :
0 commit comments