Coinbase Pro API Authentication failed in Python - coinbase-api

I have used the following code to make a Coinbase API request, but I keep getting the 401 authentication error.
My request seems to be providing the right header information and I do have an active API in Coinbase Pro.
Any idea what I am doing wrong?
import hashlib
import hmac
from datetime import datetime
import requests
from requests.auth import AuthBase
URL = 'https://api.exchange.coinbase.com'
request_path = '/accounts/accountid'
#coinbase pro
API_KEY = {API_KEY}
API_SECRET = {API_SECRET}
passphrase = {passphrase}
class Auth(AuthBase):
VERSION = b'2021-03-30'
def __init__(self, API_KEY, API_SECRET, passphrase):
self.API_KEY = API_KEY
self.API_SECRET = API_SECRET
self.passphrase = passphrase
def __call__(self, request):
timestamp = datetime.now().strftime('%s')
message = f"{timestamp}{request.method}{request.path_url}{request.body or ''}"
signature = hmac.new(self.API_SECRET.encode(),
message.encode('utf-8'),
digestmod=hashlib.sha256)
signature_hex = signature.hexdigest()
request.headers.update({
'CB-ACCESS-SIGN': signature_hex,
'CB-ACCESS-TIMESTAMP': timestamp.encode(),
'CB-ACCESS-KEY': self.API_KEY.encode(),
'CB-VERSION': self.VERSION,
'CB-ACCESS-PASSPHRASE': self.passphrase,
'Accept': 'application/json'
})
return request
auth = Auth(API_KEY, API_SECRET,passphrase)
response = requests.request("GET",f'{URL}{request_path}', auth=auth)
response

Related

Flask and React CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request

I am trying to connect my react frontend to my flask api backend. Note that flask-cors is already installed.
I initiated CORS as CORS(app) . the login passes but I keep getting this error when I go to project route:
Access to fetch at 'http://192.168.101.4:5000/project' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
My init.py file:
from flask import Flask, request, make_response
from .extensions import db, migrate, jwt, mail, CORS
from .models import TokenBlocklist
from .routes.base import base
from .routes.auth import auth
from .routes.core import core
from .routes.admin import admin
from .routes.user import user
from .routes.project import project
def create_app(config_file='config.py'):
app = Flask(__name__)
app.config.from_pyfile(config_file)
#jwt.token_in_blocklist_loader
def check_if_token_revoked(jtw_header, jwt_payload: dict)->bool:
jti = jwt_payload['jti']
token = db.session.query(TokenBlocklist.id).filter_by(jti=jti).scalar()
return token is not None
# initiate
db.init_app(app)
migrate.init_app(app, db)
jwt.init_app(app)
mail.init_app(app)
CORS(app)
app.register_blueprint(base)
app.register_blueprint(auth, url_prefix='/auth')
app.register_blueprint(core, url_prefix='/core')
app.register_blueprint(admin, url_prefix='/admin')
app.register_blueprint(user, url_prefix='/user')
app.register_blueprint(project, url_prefix='/project')
return app
my auth.py:
"""
Route: endpoints for authentication
"""
from flask import Blueprint, jsonify, request, current_app, url_for, make_response
import datetime
import uuid
import validators
from itsdangerous import URLSafeTimedSerializer
from flask_jwt_extended import create_access_token, create_refresh_token, get_jwt_identity, jwt_required, unset_jwt_cookies, get_jwt, set_access_cookies, set_refresh_cookies
from werkzeug.security import generate_password_hash
from flask_cors import CORS
from ..utils import send_mail
from ..extensions import db, status, jwt
from ..models import User, TokenBlocklist
auth = Blueprint('auth', __name__)
CORS(auth)
#auth.route('/confirm-email/<token>')
def confirm_email(token):
s = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
try:
email = s.loads(token, salt='email-confirm', max_age=200)
# mark user mail as confirmed
user = User.query.filter_by(email=email).first()
if not user.is_confirmed:
user.is_confirmed = True
db.session.commit()
return jsonify(msg='email confirmed'), status.ok
except:
return jsonify(msg = False), status.bad
#auth.route('/register', methods=['POST'])
def register():
"""
recieve request->username, email, password
check username & email exists or not, if not hash password and store.
send email with confirmation link
"""
data = request.get_json()
username = data['username']
email = data['email']
password = data['password']
# check existance of requirements in request json
if not username or not email or not password:
return jsonify(msg='missing json data'), status.bad
# email validations
if not validators.email(email):
return jsonify(msg='invalid email address'),
# check if username and email is taken
user = User.query.filter_by(username=username).first()
if user:
return jsonify(msg='username already taken')
user = User.query.filter_by(email=email).first()
if user:
return jsonify(msg='email already taken')
# save new user in db
new_user = User(
username = username,
email = email,
password = generate_password_hash(password, 'sha256'), # probably not a good practice to use User
public_id = uuid.uuid4()
)
try:
db.session.add(new_user)
db.session.commit()
except:
return jsonify(msg='could not save')
# create email confirmation link
token = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
token = token.dumps(email, salt='email-confirm')
link = url_for('auth.confirm_email', token=token, _external=True)
# send mail
body = f'confirmation link: {link}'
mail_sent = send_mail(recipient=email, body=body, subject='Linkage Email Confirmation')
if not mail_sent:
return jsonify(msg= 'email could not be sent')
return jsonify(msg= 'mail sent' ,email=email, token=token), 201
#auth.route('/login', methods=['POST'])
def login():
"""
recieve json data->email, password
check if email exists,
check user's hashed password and if email is confirmed.
generate refresh and access token and return
"""
data = request.get_json()
email = data['email']
password = data['password']
user = User.query.filter_by(email=email).first()
# email not found
if not user:
return make_response(
'User not found',
401,
{'WWW-Authenticate' : 'Basic realm ="could not verify"'}
)
# email found
verified = user.verify_password(password)
if verified is False:
return make_response(
'password mismatch',
401,
{'WWW-Authenticate' : 'Basic realm ="could not verify"'}
)
# authenticated, now generate tokens
user_public_id = user.public_id
refresh_token = create_refresh_token(identity=user_public_id)
access_token = create_access_token(identity=user_public_id)
# i am totally not sure about the following, but the fe dev *insists*
response = jsonify({"x-access-token": access_token})
response.set_cookie("refresh_token_cookie", refresh_token)
return response, 200
And Finally my project.py:
from datetime import datetime
from flask import Blueprint, jsonify, request, make_response
from flask_jwt_extended import get_jwt_identity, jwt_required
from ..extensions import db
from ..models import Project
project = Blueprint('project', __name__)
# this route must be deleted before production
#project.route('/', methods=['GET'])
#jwt_required()
def all_projects():
user_public_id = get_jwt_identity()
projects = Project.query.filter_by(user_public_id=user_public_id).all()
projects_data = []
for project in projects:
project_data = {}
project_data['id'] = project.id
project_data['domain'] = project.domain
project_data['name'] = project.name
project_data['user_public_id'] = project.user_public_id
project_data['wp_password'] = project.wp_password
project_data['wp_username'] = project.wp_username
project_data['date_added'] = project.date_added
projects_data.append(project_data)
return jsonify(projects = projects_data), 20
CORS related configs in my config.py file:
#CORS
CORS_ALLOW_HEADERS = ['Content-Type', 'Authorization']
CORS_SUPPORTS_CREDENTIALS = True
CORS_HEADERS = ['Content-Type', 'Authorization']
I am totally lost here. I don't know where is the redirect is happening.
Thank you for your time.

Problems with find_one_and_update using Pymongo/Flask with React application

I am working on the administrator part of a beginner's project I'm working on. I'm building in React.js with Pymongo/Flask connected to MongoDB Atlas for database storage. The page I'm working on allows the administrator to query the database to return all the users for a particular course they are taking or role they have (instructor or administrator). The returned data is mapped over to child components in React with a series of input fields using the defaultValue being populated by the props for the children (i.e. first name, last name, email, etc.). I'm saving new values to the child components' states and using JSON.stringify to make an axios.patch request. I'd like to be able to alter any user's information and submit it to the Mongo DB Atlas server, but am having some issues.
Here is what I think would be the necessary code from the front end:
saveChanges(id, data) {
var token = window.sessionStorage.getItem("token")
const updata = JSON.stringify(data)
axios.patch(`http://127.0.0.1:5000/update-instructor/${id}`, JSON.stringify({updata}), { headers: {"Authorization" : `Bearer ${token}`}})
.catch(error => {
console.log("There was an error with the patch request to instructor", error)
})
}
On the backend, this is the route that axios is calling:
#app.route('/update-instructor/<id>', methods=['GET', 'PATCH'])
def update_one_instructor(id):
id = ObjectId(id)
id_call = {"_id" : id}
updateObject = request.get_json(force=True)
instructors.find_one_and_update(id_call,
{ "$set" : { updateObject } },
return_document = ReturnDocument.AFTER)
The imports and setup of my flask/Pymongo:
import datetime
from distutils.log import error
import json
import pymongo
from bson.objectid import ObjectId
from bson import json_util
from flask_jwt_extended import create_access_token
from flask_jwt_extended import decode_token
from flask_jwt_extended import JWTManager
from flask_jwt_extended import jwt_required
from flask import Flask, jsonify, make_response, Response, request
from flask_cors import CORS, cross_origin
from pymongo import ReturnDocument
from werkzeug.security import generate_password_hash, check_password_hash
CONNECTION_URL = *connection url*
app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'
cors = CORS(app)
app.config['JWT_SECRET_KEY'] = *secret key*
jwt = JWTManager(app)
try:
client = pymongo.MongoClient(CONNECTION_URL, serverSelectionTimeoutMS = 10000)
except:
print("Error - cannot connect to database")
Database = client.get_database(*database name*)
instructors = Database.instructors
I'm getting several issues. On the front end in Chrome, I am getting:
Access to XMLHttpRequest at 'http://127.0.0.1:5000/update-instructor/*string of ObjectID*' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
as well as:
PATCH http://127.0.0.1:5000/update-instructor/*string of ObjectID* net::ERR_FAILED
On the backend I'm getting a 400 error:
127.0.0.1 - - [14/Mar/2022 17:17:43] "OPTIONS /update-instructor/*string of ObjectID* HTTP/1.1" 400 -
Might be unecessary information here; but I'm not sure what is relevant. Any ideas on how I can get this patch request to go through and update MongoDB Atlas and, subsequently, the state in my parent component?
I found the solution. It seems it was an error in my Pymongo/Flask setup.
#app.route('/update-user/<id>', methods=['GET', 'PATCH'])
def update_one_user(id):
id = ObjectId(id)
updateObject = request.get_json()
jsonify(updateObject)
result = users.find_one_and_update({"_id" : id},
{ "$set" : updateObject },
return_document = ReturnDocument.AFTER)
return "User Updated"
I also did some refactoring, so the route is slightly changed. Basically it seems that using fewer variables as well as well as removing the {} from updateObject did the trick. But I also refactored my front end code to
saveChanges(id, data) {
let config = {
headers: {
"Content-Type": "application/json",
'Access-Control-Allow-Origin': '*'
}
}
axios.patch(`http://127.0.0.1:5000/update-user/${id}`, JSON.stringify(data), config)
.catch(error => {
console.log("There was an error with the patch request to instructor", error)
})
}
It now includes some extra headers for CORS, but was was pointed out to me, it was the http 400 that was causing the CORS issue.

Unable to send POST request from the React frontend to Django Rest Framework using serializer?

I have been trying to POST a request with data using fetch in React.js. How can I receive all the data sent in the body of the request options? I am attaching the serializer models for better understanding.
React Frontend(sending the post request with the data)
handleOnSubmit = (event)=>{
const requestOptions = {
method : "POST",
headers : {
Accept: "application/json",
"Content-Type":"application/json"},
body : JSON.stringify({
name:this.state.name,
est:this.state.est,
org:this.state.org
}),
};
fetch("api/add-company", requestOptions).then((response)=>{return response.json()}).then((data)=>{
console.log(data)
})
event.preventDefault();
}
models.py
class Company(models.Model):
name = models.CharField(max_length=30, blank= False, null=False, unique=True)
established = models.IntegerField()
origin = models.CharField(max_length=64, null=False, blank=False)
serializers.py
from rest_framework import serializers
from .models import Company,Brand
class AddCompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ['name', 'established', 'origin']
extra_kwargs = {'name':{'required':False},'established':{'required':False},'origin':{'required':False}}
If you want to get the data send as body of POST request then you can use request.POST.get() method. In your case it would be:
name = json.loads(request.POST.get('name'))
est = json.loads(request.POST.get('est'))
org = json.loads(request.POST.get('org'))
You need to save your serializer.
if serializer.is_valid():
response = serializer.save()
return Response(response.data, status=status.HTTP_201_CREATED)

What is the right way to specify headers using axios?

I'm wrestling with cross origin headers while testing my app:
react side:
const url = "http://localhost:5000/blog/posts";
const headers = { headers: "Access-Control-Allow-Origin" };
axios.post(url, data, headers).then( ...
Flask backend __init__.py :
...
...
from flask_cors import CORS
def create_app(script_info=None):
app = Flask(__name__)
from project.api.blog import blog_blueprint
from project.api.auth import auth_blueprint
CORS(blog_blueprint, resources={'origin': ['http://localhost:3000']})
app.register_blueprint(blog_blueprint)
app.register_blueprint(auth_blueprint)
return app
the above gives me an exception in the catch block of the try-catch statement:
TypeError: name.toUpperCase is not a function
using Flask's defaults which means exposing the endpoint to any domain:
from project.api.blog import blog_blueprint
from project.api.auth import auth_blueprint
CORS(blog_blueprint)
gives me Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/blog/posts. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
I've also tried to use a decorator from Flask-CORS:
from flask_cors import cross_origin
class BlogPosts(Resource):
#cross_origin()
def post(self):
parser.add_argument('category', type=str)
parser.add_argument('title', type=str)
parser.add_argument('post', type=str)
args = parser.parse_args()
new_post = Posts(title=args.title, category=args.category, post=args.post)
db.session.add(new_post)
db.session.commit()
return {'status': 'success', 'message': 'post added'}, 201
Any help is much appreciated.
Strangely, I fixed my problem by refactoring my code into function-based view:
CORS(blog_blueprint)
#blog_blueprint.route('/posts', methods=['GET', 'POST'])
#cross_origin()
def blog_posts():
if request.method == 'POST':
post_data = request.get_json()
category = post_data.get('category')
title = post_data.get('title')
post = post_data.get('post')
new_post = Posts(title=title, category=category, post=post)
db.session.add(new_post)
db.session.commit()
return {'status': 'success', 'message': 'post added'}, 201
return {'status': 'success', 'message': [post.to_json() for post in Posts.query.filter_by(category=category)]}, 200
I'm not very happy with this because Flask's CORS library should work same regardless if I'm using class-based or function-based view for handling APIs.

Angular 2 POST giving 403 CSRF error posting to Django server

I am struggling with 403/CSRF issues when trying to use Angular 2 to POST to my Django server.
Both my server code and my Angular code are running on the same 127.0.0.1 server.
When the Angular code is run the server returns a 403 4612 error
My Django View code looks like this (I am using the Django REST Framework):
rom django.utils import timezone
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.models import User
from .models import Item, Seen, Keyword, Flag
from django.utils.decorators import classonlymethod
from django.views.decorators.csrf import csrf_exempt
from rest_framework import viewsets
from items.serializers import ItemSerializer, UserSerializer
from rest_framework.authentication import SessionAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return # To not perform the csrf check previously happening
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all().order_by('-date_added')
serializer_class = ItemSerializer
authentication_classes = (CsrfExemptSessionAuthentication, )
#permission_classes = [IsAccountAdminOrReadOnly]
"""
Use the API call query params to determing what to return
API params can be:
?user=<users_id>&num=<num_of_items_to_return>&from=<user_id_of_items_to_show>
"""
def get_queryset(self):
this_user = self.request.query_params.get('user', None)
restrict_to_items_from_user_id = self.request.query_params.get('from', None)
quantity = self.request.query_params.get('num', 20)
if restrict_to_items_from_user_id is not None:
queryset = Item.objects.filter(owner=restrict_to_items_from_user_id, active=True).order_by('-date_added')[0:int(quantity)]
elif this_user is not None:
queryset = Item.objects.filter(active=True, credits_left__gt=0).exclude(pk__in=Seen.objects.filter(user_id=this_user).values_list('item_id', flat=True))[0:int(quantity)]
else:
queryset = Item.objects.filter(active=True, credits_left__gt=0)[0:int(quantity)]
return queryset
My Angular 2 code that does the POST looks like this:
import {Injectable, Inject} from 'angular2/core';
import {Http, Headers, HTTP_PROVIDERS} from 'angular2/http';
import {UserData} from './user-data';
import 'rxjs/add/operator/map';
#Injectable()
export class ConferenceData {
static get parameters(){
return [[Http], [UserData]];
}
constructor(http, user) {
// inject the Http provider and set to this instance
this.http = http;
this.user = user;
}
load() {
// Example of a PUT item
let body = JSON.stringify({ url: 'fred', item_type: 'P', owner_id: 2 });
let headers = new Headers();
headers.append('Content-Type', 'application/json');
this.http.post('http://127.0.0.1:8000/api/items/', body, {
headers: headers
})
.subscribe(
data => {
alert(JSON.stringify(data));
},
err => this.logError(err.json().message),
() => console.log('Authentication Complete')
);
}
}
I find CSRF issues really difficult to get to grips with!
EDIT: Added CORS settings
My CORS settings look like this:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
'veeu.co',
'127.0.0.1'
)
CORS_ORIGIN_REGEX_WHITELIST = ()
CORS_URLS_REGEX = '^.*$'
CORS_ALLOW_METHODS = (
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'UPDATE',
'OPTIONS'
)
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'x-csrftoken'
)
CORS_EXPOSE_HEADERS = ()
CORS_ALLOW_CREDENTIALS = False
Rather than disabling the CSRF protection, you can add the token as a header to your ajax requests. See the docs, in particular the last section for AngularJS.
You might have to use csrf_ensure for the initial Django view, to ensure that Django sets the csrf cookie.

Resources