Config
app.config['JWT_COOKIE_CSRF_PROTECT'] = True
app.config["JWT_TOKEN_LOCATION"] = ['cookies']
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=0.005)
class LogOut(Resource):
#jwt_required()
def get(self):
response = make_response(render_template('home.html', is_login=False))
unset_jwt_cookies(response)
return response
#app.after_request
def refresh_expiring_jwts(response):
try:
exp_timestamp = get_jwt()["exp"]
now = datetime.now(timezone.utc)
target_timestamp = datetime.timestamp(now + timedelta(minutes=30))
if target_timestamp > exp_timestamp:
access_token = create_access_token(identity=get_jwt_identity())
set_access_cookies(response, access_token)
return response
except (RuntimeError, KeyError):
# Case where there is not a valid JWT. Just return the original respone
return response
I am trying to write code for implict refresh of access tokens using Flask-JWT-Extended library and having the below error.
In the above code login is working properly but if we access the logout the access token cookies are not being deleted.
Can anyone explain why it is not working?
While trying to register my receiver endpoint in order to start receiving RISC indications from google, I constantly get the same reply:
403 Client Error: Forbidden for url:
https://risc.googleapis.com/v1beta/stream:update
I have created the service with the Editor Role and using the json key I created as requested on the integration guide.
This is my provisioning code I use to do that:
import json
import time
import jwt # pip install pyjwt
import requests
def make_bearer_token(credentials_file):
with open(credentials_file) as service_json:
service_account = json.load(service_json)
issuer = service_account['client_email']
subject = service_account['client_email']
private_key_id = service_account['private_key_id']
private_key = service_account['private_key']
issued_at = int(time.time())
expires_at = issued_at + 3600
payload = {'iss': issuer,
'sub': subject,
'aud': 'https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService',
'iat': issued_at,
'exp': expires_at}
encoded = jwt.encode(payload, private_key, algorithm='RS256',
headers={'kid': private_key_id})
return encoded
def configure_event_stream(auth_token, receiver_endpoint, events_requested):
stream_update_endpoint = 'https://risc.googleapis.com/v1beta/stream:update'
headers = {'Authorization': 'Bearer {}'.format(auth_token)}
stream_cfg = {'delivery': {'delivery_method': 'https://schemas.openid.net/secevent/risc/delivery-method/push',
'url': receiver_endpoint},
'events_requested': events_requested}
response = requests.post(stream_update_endpoint, json=stream_cfg, headers=headers)
response.raise_for_status() # Raise exception for unsuccessful requests
def main():
auth_token = make_bearer_token('service_creds.json')
configure_event_stream(auth_token, 'https://MY-ENDPOINT.io',
['https://schemas.openid.net/secevent/risc/event-type/sessions-revoked',
'https://schemas.openid.net/secevent/oauth/event-type/tokens-revoked',
'https://schemas.openid.net/secevent/risc/event-type/account-disabled',
'https://schemas.openid.net/secevent/risc/event-type/account-enabled',
'https://schemas.openid.net/secevent/risc/event-type/account-purged',
'https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required'])
if __name__ == "__main__":
main()
Also tested my auth token and it seems as the integration guide suggests.
Could not find 403 forbidden on the error code reference table there.
You can check for error description in the response body and match that against the possible reasons listed here!
i am having trouble trying to mock test the on-boarding process of stripe connect. I am just learning how to use mock and i am struggling with the StripeAuthorizeCallbackView. the process is as follows: A user reaches the StripeAuthorizeView which sends them to the stripe api to sign up for an account. Once they successfully sign up for an account their redirected back to my platform and stripe sends a temporary code which i then send back to stripe with my api keys. Once i have sent the information back to stripe they then return me credentials for the user being the stripe_user_id.
Here is the two views in question:
import urllib
import requests
class StripeAuthorizeView(LoginRequiredMixin, View):
def get(self, request):
url = 'https://connect.stripe.com/express/oauth/authorize?'
user = self.request.user
if user.account_type == 'Business':
business_type = 'company'
else:
business_type = 'individual'
params = {
'response_type': 'code',
'scope': 'read_write',
'client_id': settings.STRIPE_CONNECT_CLIENT_ID,
'redirect_uri': f'http://127.0.0.1:8000/accounts/stripe/oauth/callback',
'stripe_user[email]' : user.email,
'stripe_user[business_type]' : business_type,
'stripe_user[url]' : 'http://127.0.0.1:8000/accounts/user/%s/' %user.pk,
}
url = f'{url}?{urllib.parse.urlencode(params)}'
return redirect(url)
lass StripeAuthorizeCallbackView(LoginRequiredMixin, View):
def get(self, request):
code = request.GET.get('code')
if code:
data = {
'client_secret': settings.STRIPE_SECRET_KEY,
'grant_type': 'authorization_code',
'client_id': settings.STRIPE_CONNECT_CLIENT_ID,
'code': code
}
url = 'https://connect.stripe.com/oauth/token'
resp = requests.post(url, params=data)
stripe_user_id = resp.json()['stripe_user_id']
stripe_access_token = resp.json()['access_token']
stripe_refresh_token = resp.json()['refresh_token']
user = self.request.user
user.stripe_access_token = stripe_access_token
user.stripe_user_id = stripe_user_id
user.stripe_refresh_token = stripe_refresh_token
user.save()
notify.send(sender=user, recipient=user,
verb='You have succesfully linked a stripe account. You can now take payments for sales.',
level='info')
redirect_url = reverse('account', kwargs={'pk': user.pk})
response = redirect(redirect_url)
return response
else:
user = self.request.user
notify.send(sender=user, recipient=user,
verb='Your attempt to link a stripe account failed. Please contact customer support.',
level='warning')
url = reverse('account', kwargs={'pk': user.pk})
response = redirect(url)
return response
I am not very worried about testing the StripeAuthorizeView a lot. I am more trying to figure out how to test the StripeAuthorizeCallbackView. All i can figure out is that i will need to mock both the code returned and then mock the following requests.post. This test is important to confirm my platform is linking the users credentials after the on-boarding process. Any help on this will be greatly appricated.
edit:
So far i have the following :
#classmethod
def setUpTestData(cls):
cls.test_user = User.objects.create_user(
password='test',
full_name='test name',
email='test#test.com',
address='1 test st',
suburb='test',
state='NSW',
post_code='2000',
contact_number='0433335333' )
#patch('requests.get')
def test_authorizecallback_creates_stripe_details(self, get_mock):
code = requests.get('code')
user = self.test_user
self.client.login(email='test#test.com', password='test')
mocked = ({'stripe_user_id' : '4444','stripe_access_token' : '2222',
'stripe_refresh_token' : '1111' })
with mock.patch('requests.post', mock.Mock(return_value=mocked)):
response = self.client.get('/accounts/stripe/oauth/callback/',
{'code' : '1234'})
self.assertEqual(user.stripe_access_token, '222')
message = list(response.context.get('messages'))[0]
however i keep getting:
File "C:\Users\typef\Desktop\Projects\python_env\fox-listed\Fox-Listed\fox-listed\user\views.py", line 142, in get
stripe_user_id = resp.json()['stripe_user_id']
AttributeError: 'dict' object has no attribute 'json'
the actual response that the StripeAuthorizeCallBackView gives is:
{'access_token': 'sk_test_1KyTG74Ouw65KYTR1O03WjNA00viNjcIfO', 'livemode': False, 'refresh_token': 'rt_H3Vrhd0XbSH7zbmqfDyMNwolgt1Gd7r4ESBDBr5a4VkCzTRT', 'token_type': 'bearer', 'stripe_publishable_key': 'pk_test_**********', 'stripe_user_id': 'acct_1GVOpAF7ag87i2I6', 'scope': 'express'}
Looks like i got it, if there is a flaw here let me know but here is what i have:
class TestStripeAuthorizeCallbackView:
#patch('user.views.requests')
def test_authorizecallback_creates_stripe_details(self, requests_mock):
json = { 'stripe_user_id' : '4444', 'access_token' : '2222', 'refresh_token' : '1111'}
requests_mock.post.return_value.json.return_value = json
user = mixer.blend('user.CustomUser', stripe_user_id=None, access_token=None, refresh_token=None)
req = RequestFactory().get('/', data={'code' : '1234'})
middleware = SessionMiddleware()
middleware.process_request(req)
req.session.save()
messages = FallbackStorage(req)
setattr(req, '_messages', messages)
req.user = user
resp = StripeAuthorizeCallbackView.as_view()(req)
assert resp.status_code == 302 ,'should redirect to success url'
assert user.stripe_user_id == '4444', 'should assign stripe_user_id to user'
assert user.stripe_access_token == '2222', 'should assign an access_token'
assert user.stripe_refresh_token == '1111', 'should assign a refresh_token'
What you're describing isn't mocking so much as it is end-to-end testing, connecting actual test accounts, which you can do.
As long as you're using a test client_id then when you are redirected to Stripe to create the account you can skip the form via a link and get directed back to your site with a real (test mode) oauth code.
Essentially you can set this up and actually go through the flow to create & connect new disposable test Stripe accounts.
I am having trouble getting my client and server for a simple AWS Cognito authorization to agree on what the token should look like.
My client uses boto3 and requests. I pass the authorization in the header which I've seen in more than half of tutorials but I've also seen use of the auth parameter which I am not using.
Here's my server:
from flask import request, jsonify, make_response
import flask.json
from flask_jwt_extended import (
JWTManager, jwt_required, create_access_token,
get_jwt_identity
)
app = flask.Flask(__name__)
# from: https://flask-jwt-extended.readthedocs.io/en/stable/basic_usage/
# Setup the Flask-JWT-Extended extension
app.config['JWT_SECRET_KEY'] = 'super-secret' # Change this!
jwt = JWTManager(app)
#app.route("/auth_test")
#jwt_required
def auth_test ():
current_user = get_jwt_identity()
return jsonify({"current_user": "current_user"})
if __name__ == "__main__":
app.run(debug=True)
One clue here is that JWT_SECRET_KEY is copied from a tutorial but I'm unclear on what I need to change it to. Perhaps this is my issue but if it is I don't see the solution or what to change it to.
Here's my client:
import requests
import boto3
host = "http://127.0.0.1:8000"
region = '...'
user_pool_id = '...'
username = '...'
password = '...'
app_client_id = '...'
client = boto3.client('cognito-idp', region_name = region)
auth_response = client.admin_initiate_auth(
UserPoolId = user_pool_id,
ClientId = app_client_id,
AuthFlow = 'ADMIN_NO_SRP_AUTH',
AuthParameters = {
'USERNAME' : username,
'PASSWORD' : password
}
)
id_token = auth_response['AuthenticationResult']['IdToken']
response = requests.get(host + "/auth_test" , headers = { 'Authorization': id_token })
print(response.json())
It prints:
{'msg': "Bad Authorization header. Expected value 'Bearer '"}
This indicates that I should be passing "Bearer " + id_token instead of just id_token but this is contrary to most tutorials I've read and furthermore when I do that I still get the same error.
Anyone know what I'm doing wrong?
EDIT:
I have made some changes due to the comments. I have added
app.config['JWT_ALGORITHM'] = 'RS256'
app.config['JWT_DECODE_ALGORITHMS'] = ['RS256']
#app.config['JWT_PUBLIC_KEY'] = '...' # value that I got from https://cognito-idp.us-east-1.amazonaws.com/<my pool id>/.well-known/jwks.json. There were two entries I tried both values found in kid
RS256 matches Cognito's encoding so I think I need to set that for my server. However I now simply get this error when running the demo:
ValueError: Could not deserialize key data.
Thank you for the help!
Okay, so after a user logs in, I want to get their profile data. So the way I tried doing that was via boto3.client('cognito-idp').get_user but it keeps returning:
NotAuthorizedException: An error occurred (NotAuthorizedException) when calling the GetUser operation: Access Token does not have required scopes
To my knowledge, I have put every single built in Cognito scope and I am unsure why it is not working. Any help would be appreciated!
My Auth Script
scope = request.args.get(
'scope',
'email phone profile openid')
sumukey = make_session(scope=scope.split(' '))
authorization_url, state = sumukey.authorization_url(AUTHORIZATION_BASE_URL)
session['oauth2_state'] = state
return redirect(authorization_url)
My Return
sumukey = make_session(state=session.get('oauth2_state'))
token = sumukey.fetch_token(
TOKEN_URL,
client_secret=OAUTH2_CLIENT_SECRET,
authorization_response=request.url)
session['oauth2_token'] = token
return redirect(url_for('.index'))
Current Attempt to get data
client = boto3.client('cognito-idp')
response = client.get_user(
AccessToken=session['oauth2_token']['access_token']
)
return str(jsonify(response))
make_session
return OAuth2Session(
scope=scope,
client_id=OAUTH2_CLIENT_ID,
token=token,
state=state,
redirect_uri=OAUTH2_REDIRECT_URI,
auto_refresh_kwargs={
'client_id': OAUTH2_CLIENT_ID,
'client_secret': OAUTH2_CLIENT_SECRET,
},
auto_refresh_url=TOKEN_URL,
token_updater=token_updater)