@@ -87,25 +87,29 @@ def gen_payload_data():
87
87
88
88
Avoids `invalid_grant` by getting a new `exp` value during signing
89
89
"""
90
-
91
90
payload_data = {
92
- "audience" : 'api.meetup.com' ,
93
- "kid" : SIGNING_KEY_ID ,
94
91
"sub" : SELF_ID ,
95
- "iss" : CLIENT_SECRET ,
96
- "exp" : time .time () + int (JWT_LIFE_SPAN )
92
+ "iss" : CLIENT_ID ,
93
+ "aud" : "api.meetup.com" ,
94
+ "exp" : int (time .time () + JWT_LIFE_SPAN )
97
95
}
98
-
99
96
return payload_data
100
97
101
98
102
99
def sign_token ():
103
100
"""Generate signed JWT"""
104
101
102
+ # Define headers exactly as specified in docs
103
+ jwt_headers = {
104
+ "kid" : SIGNING_KEY_ID ,
105
+ "typ" : "JWT" ,
106
+ "alg" : "RS256"
107
+ }
108
+
105
109
payload_data = gen_payload_data ()
106
110
107
111
payload = jwt .encode (
108
- headers = headers ,
112
+ headers = jwt_headers ,
109
113
payload = payload_data ,
110
114
key = private_key ,
111
115
algorithm = 'RS256'
@@ -121,7 +125,8 @@ def verify_token(token):
121
125
jwt .decode (
122
126
jwt = token ,
123
127
key = public_key ,
124
- issuer = CLIENT_SECRET ,
128
+ issuer = CLIENT_ID ,
129
+ audience = "api.meetup.com" ,
125
130
verify = True ,
126
131
algorithms = ['RS256' ]
127
132
)
@@ -134,6 +139,7 @@ def verify_token(token):
134
139
jwt .exceptions .InvalidTokenError ,
135
140
jwt .exceptions .InvalidSignatureError ,
136
141
jwt .exceptions .InvalidIssuerError ,
142
+ jwt .exceptions .InvalidAudienceError ,
137
143
) as e :
138
144
print (f"{ Fore .RED } { error :<10} { Fore .RESET } { e } " )
139
145
sys .exit (1 )
@@ -142,18 +148,30 @@ def verify_token(token):
142
148
def get_access_token (token ):
143
149
"""Post token to auth server to get access token"""
144
150
151
+ # Headers for the token request
152
+ request_headers = {
153
+ "Content-Type" : "application/x-www-form-urlencoded"
154
+ }
155
+
156
+ # Payload exactly as specified in docs
157
+ # https://www.meetup.com/api/authentication/#p04-jwt-flow-section
145
158
payload = {
146
- "grant_type" : 'urn:ietf:params:oauth:grant-type:jwt-bearer' ,
147
- "assertion" : token ,
148
- "redirect_uri" : REDIRECT_URI ,
149
- "client_id" : CLIENT_ID ,
150
- "client_secret" : CLIENT_SECRET ,
151
- "audience" : 'api.meetup.com' ,
152
- "exp" : time .time () + int (JWT_LIFE_SPAN )
159
+ "grant_type" : "urn:ietf:params:oauth:grant-type:jwt-bearer" ,
160
+ "assertion" : token
153
161
}
154
162
payload = urlencode (payload )
155
163
156
- return requests .request ("POST" , TOKEN_URL , headers = headers , data = payload )
164
+ try :
165
+ response = requests .request ("POST" , TOKEN_URL , headers = request_headers , data = payload )
166
+ response .raise_for_status ()
167
+ return response .json ()
168
+ except requests .exceptions .HTTPError as e :
169
+ print (f"{ Fore .RED } { error :<10} { Fore .RESET } HTTP Error: { e } " )
170
+ print (f"Response: { response .text } " )
171
+ return None
172
+ except requests .exceptions .RequestException as e :
173
+ print (f"{ Fore .RED } { error :<10} { Fore .RESET } Request failed: { e } " )
174
+ return None
157
175
158
176
159
177
def main ():
@@ -163,12 +181,17 @@ def main():
163
181
token = sign_token ()
164
182
165
183
# verify JWT
166
- verify_token (token )
184
+ if not verify_token (token ):
185
+ print (f"{ Fore .RED } { error :<10} { Fore .RESET } Token verification failed" )
186
+ return None
167
187
168
188
# get access and refresh tokens
169
- res = get_access_token (token )
189
+ tokens = get_access_token (token )
190
+ if not tokens :
191
+ print (f"{ Fore .RED } { error :<10} { Fore .RESET } Failed to get access token" )
192
+ return None
170
193
171
- return res . json ()
194
+ return tokens
172
195
173
196
174
197
if __name__ == "__main__" :
0 commit comments