@@ -33,6 +33,14 @@ def generate_token():
33
33
return secrets .token_hex (nbytes = 32 )
34
34
35
35
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
+
36
44
class ApiTokenManager (ControlOutboxProducingManager ):
37
45
def create (self , * args , ** kwargs ):
38
46
token_type : AuthTokenType | None = kwargs .get ("token_type" , None )
@@ -128,6 +136,8 @@ def _plaintext_token(self):
128
136
129
137
if plaintext_token is not None :
130
138
setattr (self , f"_{ manager_class_name } __plaintext_token" , None )
139
+ else :
140
+ raise PlaintextSecretAlreadyRead ()
131
141
132
142
return plaintext_token
133
143
@@ -144,9 +154,18 @@ def _plaintext_refresh_token(self):
144
154
self , f"_{ manager_class_name } __plaintext_refresh_token" , None
145
155
)
146
156
147
- if plaintext_refresh_token is not None :
157
+ if plaintext_refresh_token :
148
158
setattr (self , f"_{ manager_class_name } __plaintext_refresh_token" , None )
149
159
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
+
150
169
return plaintext_refresh_token
151
170
152
171
def save (self , * args : Any , ** kwargs : Any ) -> None :
0 commit comments