Authorization VK API error: u'{"error":"invalid_request","error_description":"Security Error"}' - python-2.7

I'm trying to authorize from my djano-app on vk.com. I'm using requests and client authorization. I'm trying to authorize by this way and getting an error:
{"error":"invalid_request","error_description":"Security Error"}
Internet suggests to re-login on VK in browser, but there isn't any solution for authorization from code.
My code:
class VkApiSingleton(object):
api_version = '5.95'
def __init__(self,
app_id=config.APP_ID,
login=config.ACCOUNT_LOGIN,
pswd=config.ACCOUNT_PASSWORD,
permissions='video,offline,groups'
):
# type: (int, str, str, str) -> None
self.app_id = app_id
self.app_user_login = login
self.app_user_pass = pswd
self.access_token = None
self.user_id = None
self.session = requests.Session()
self.form_parser = FormParser()
self.permissions = permissions
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'):
cls.instance = super(VkApiSingleton, cls).__new__(cls, *args, **kwargs)
return cls.instance
#property
def get_session(self):
return self.session
def _parse_form(self, response):
# type: (requests.models.Response) -> None
self.form_parser = FormParser()
try:
self.form_parser.feed(str(response.content))
except Exception as err:
logger.exception(
'Error checking HTML form',
extra={'Error body': str(err)}
)
def _submit_form(self, **kwargs):
# type: (dict) -> requests.models.Response
if self.form_parser.method == 'post':
payload = copy.deepcopy(self.form_parser.params)
if kwargs.get('is_login', False):
payload.update({
'email': self.app_user_login,
'pass': self.app_user_pass
})
with self.get_session as session:
try:
return session.post(self.form_parser.url, data=payload)
except Exception as err:
logger.exception(
'Error submitting auth form',
extra={'Error body': str(err)}
)
raise VkApiError('Error submitting auth form: %s' % str(err))
def _log_in(self):
# type: () -> requests.models.Response
response = self._submit_form(is_login=True)
self._parse_form(response)
if response.status_code != 200:
raise VkApiError('Auth error: cant parse HTML form')
if 'pass' in response.text:
logger.error(
'Wrong login or password'
)
raise VkApiError('Wrong login or password')
return response
def _submit_permissions(self, url=None):
# type: () -> requests.models.Response
if 'submit_allow_access' in self.form_parser.params and 'grant_access' in self.form_parser.url:
return self._submit_form(token_url=url)
else:
logger.warning(
'Cant submit permissions for application'
)
def _get_token(self, response):
# type: (requests.models.Response) -> None
try:
params = response.url.split('#')[1].split('&')
self.access_token = params[0].split('=')[1]
self.user_id = params[2].split('=')[1]
except IndexError as err:
logger.error(
'Cant get access_token',
extra={'Error body': str(err)}
)
def auth(self):
auth_url = 'https://oauth.vk.com/authorize?revoke=1'
redirect_uri = 'https://oauth.vk.com/blank.html'
display = 'wap'
request_params = {
'client_id': self.app_id,
'scope': self.permissions,
'redirect_uri': redirect_uri,
'display': display,
'response_type': 'token',
'v': self.api_version
}
with self.get_session as session:
response = session.get(
auth_url,
params=request_params
)
self._parse_form(response)
if not self.form_parser.form_parsed:
raise VkApiError('Invalid HTML form. Check auth_url or params')
else:
login_response = self._log_in()
permissions_response = self._submit_permissions()
self._get_token(login_response)

If someone has a similar problem - I found some reasons of this.
1) Invalid type of authorization - try to use another type of authorization (it describes in official documentation)
2) Too many authorizations.
I solved problem like this:
1) Get token with "offline" permission by "Client Application Authorization"
2) Every time I need to use vk.api method - I am checking my token for expiring with secure method "secure.checkToken" (you need to get Service token to use this method. There are a lot of information in official documentation)
3) If my token expires - i am getting the new one.

Related

JWT Token created is not matching decoded in Flask

I`m receiving 401 in my JWT requests to the method get user infos from token (), but the tokens doesnt seem to be the same.
I already made the following checks: 1. Checked the token string is exactly the same both in the localStorage and in the create_access_token result. 2. The secret key is the same both in the token creation and in the token decoding 3. The algorithm used for encoding is also the same as the one used for decoding
What else can I do to fix it?
app = Flask(__name__)
app.config.from_object(__name__)
app.config['JWT_SECRET_KEY'] = 'example-key'
#app.route('/login', methods=['POST'])
def login():
# Extract the username and password from the request
user_email = request.get_json(silent=True).get('user_email', None)
user_password = request.get_json(silent=True).get('user_password', None)
# Validate the credentials using the UserController
user = UserController().find_user_by_user_email_and_password(user_email, user_password)
if user is False:
return jsonify({'login': False}), 401
# Calculate the expiration time
exp = datetime.utcnow() + timedelta(days=7)
# Create a JWT token with the user identity and expiration time
access_token = create_access_token(identity=user['user_id'], expires_delta=timedelta(days=7))
print("Token: '" + str(access_token) + "'")
# Return the JWT token in the response
return jsonify({'access_token': access_token}), 200
#app.route('/get_user_infos_from_token', methods=['GET'])
def get_user_infos_from_token():
try:
authorization_header = request.headers.get('Authorization')
token = authorization_header.split(" ")[1]
print("Token: '" + str(token) + "'")
decoded_token = jwt.decode(token, app.config['JWT_SECRET_KEY'], algorithms=['HS256'])
user_id = decoded_token['identity']
user = UserController().find_user_by_user_id(user_id)
if user is None:
return jsonify({'error': 'User not found'}), 404
return jsonify(user), 200
except:
return jsonify({'error': 'Invalid token'}), 401
the method below I'm using to authenticate the user, generate the token and insert in localStorage:
async login(){
let self = this;
axios.post('http://127.0.0.1:5000/login', {
user_email: self.email
, user_password: self.password
})
.then(function (response) {
localStorage.setItem('token', response.data.access_token);
console.log(response.data)
self.login_error = '';
window.alert('Uhu, deu certo! Vou te redirecionar para a página principal.');
self.$router.push({path: '/'});
})
.catch(function (error) {
self.login_error = 'Usuário ou senha incorretos. Tente novamente.';
console.log(error);
});
},
and the method below I am using to get the infos from the user, based on the token that is in the localStorage, that was created during the authentication.
mounted(){
if (localStorage.getItem('token') != null == true){
let self = this;
const token = localStorage.getItem('token').toString();
console.log(token);
axios.get('http://localhost:5000/get_user_infos_from_token', {
headers: { Authorization: `Bearer ${token}` }
}).then(response => {
self.user_data = response.data;
}).catch(error => {
console.error(error);
});
localStorage.setItem('user_data', self.user_data);
self.user_auth_flag = true;
}
},
What do I need to do to make sure the jwt decoder will use the same secret key and algorithm to decode the token generated during the authentication?
..
you did not post your jwt create and validate function. I have a jwt_helper class, you can use it for your own purpose:
PyJWT==1.4.2
import jwt
import os
class JWTHelper:
#staticmethod
def gen_auth_token(identity, email) -> str:
return JWTHelper.encode_auth_token({
"id": identity,
"email": email,
"expired": Helper.get_now_unixtimestamp() + 60 * 60, # expire in 1h,
})
#staticmethod
def encode_auth_token(payload) -> str:
secret_key = os.environ["JWT_SECRET"] # your secret
print(secret_key)
"""
Generates the Auth Token
:return String
"""
try:
return jwt.encode(
payload,
secret_key,
algorithm='HS256'
).decode('utf-8')
except Exception as e:
print(e)
#staticmethod
def decode_auth_token(token):
secret_key = os.environ["JWT_SECRET"]
"""
Decode the auth token
"""
try:
payload = jwt.decode(token, secret_key, algorithms='HS256')
return payload
except Exception as e:
print(e)
raise Unauthorized(message="Please log in again.")
# return None
#staticmethod
def validate_token(token: str):
data = JWTHelper.decode_auth_token(token)
print(data)
if not data:
raise Unauthorized(message='invalid token')
expired = data.get("expired") or None
user_id = data. Get("id") or None
if expired is None or user_id is None:
raise Unauthorized(message='invalid token')
if expired < Helper.get_now_unixtimestamp():
raise Unauthorized(message='token expired')
use your class
token = JWTHelper.gen_auth_token(
identity=1,
email="tuandao864#gmail.com",
role_id=1,
)
validate = JWTHelper.validate_token(auth_token)

Django - PUT endpoint authenticator error "wrapped_view() missing 1 required positional argument: 'request'"

So I'm trying to create a PUT endpoint for editing post data. In the endpoint the post id is given in the URL then the new post dated is inserted into the entity. The issue I'm running into is that request isn't coming through on the authenticator (I'm using Cognito to authenticate, not super important for the error). So even though you can see I'm clearly passing in data, the request isn't coming through on the wrapped_view in the cognito_authenticator function. Why is this happening? The error I'm getting is:
"wrapped_view() missing 1 required positional argument: 'request'"
Test.py
def test_edit(self):
response = self.client.put(reverse('edit_post_by_id', kwargs={'post_id': str(self.post.uuid)}),
data={'body': 'updated text #update'},
content_type='application/json',
**{'HTTP_AUTHORIZATION': f'bearer {self.cognito.access_token}'})
self.assertEqual(response.status_code, status.HTTP_200_OK)
View.py
#api_view(['PUT'])
#method_decorator(cognito_authenticator)
def edit_post(request, post_id):
try:
post = Post.objects.get(pk=post_id)
except Post.DoesNotExist:
return JsonResponse(dict(error=f'Post id: {post_id} does not exists'), status=status.HTTP_400_BAD_REQUEST)
authenticator
def cognito_authenticator(view_func=None):
if view_func is None:
return partial(cognito_authenticator)
#wraps(view_func)
def wrapped_view(request, *args, **kwargs):
# Check the cognito token from the request.
auth = request.headers.get("Authorization", None)
if not auth:
return Response(dict(error='Authorization header expected'), status=status.HTTP_401_UNAUTHORIZED)
parts = auth.split()
if parts[0].lower() != "bearer":
return Response(dict(error='Authorization header must start with bearer'),
status=status.HTTP_401_UNAUTHORIZED)
elif len(parts) == 1:
return Response(dict(error='Token not found'), status=status.HTTP_401_UNAUTHORIZED)
elif len(parts) > 2:
return Response(dict(error='Authorization header must be Bearer token'),
status=status.HTTP_401_UNAUTHORIZED)
token = parts[1]
try:
res = decode_cognito_jwt(token)
except Exception:
# Fail if invalid
return Response("Invalid JWT", status=status.HTTP_401_UNAUTHORIZED) # Or HttpResponseForbidden()
else:
# Proceed with the view if valid
return view_func(request, *args, **kwargs)
return wrapped_view
With function-based views, you don't need to use method_decorator so:
#api_view(['PUT'])
#cognito_authenticator
def edit_post(request, post_id):
...

id parameter in get request

I am new to Django and a small detail has been bothering me.I have an api endpoint that returns the details of one patient. I have made a successful get request and tested on postman. It returns data for a particular patient with id = 996(I have hard coded the id). But I need to set it so it can pick the id from params in postman instead of the hard coded one here. How can I set params and append them on the url so that I use the id fed in postman instead of hard coding? Kindly assist
views.py
class PatientDetailsView(GenericAPIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
#classmethod
#encryption_check
def get(self, request, *args, **kwargs):
try:
result = {}
auth = cc_authenticate()
res = getPatientDetails(auth["key"], id)
result = res
return Response(result, status=status.HTTP_200_OK)
except Exception as e:
error = getattr(e, "message", repr(e))
result["errors"] = error
result["status"] = "error"
return Response(result, status=status.HTTP_400_BAD_REQUEST)
api_service.py
def getPatientDetails(auth, id):
print("getting patientdetails from Callcenter")
try:
print(auth)
# print(url)
id= 996
headers = {
"Authorization": f'Token {auth}'
}
url = f'{CC_URL}/patients/v1/details/?id={id}'
print(url)
res = requests.get(url, headers=headers)
print("returning patientdetails response", res.status_code)
return res.json()
except ConnectionError as err:
print("connection exception occurred")
print(err)
return err
urls.py
path("details/", views.PatientDetailsView.as_view(), name="patient_info"),
This is the code I needed
id = request.GET.get('<id>')

Flask_restx #api.route return statement results in a TypeError

I have a problem I am not able to solve. I want to make use of http cookies in flask. This is the code from documentation:
#app.route('/token/auth', methods=['POST'])
def login():
username = request.json.get('username', None)
password = request.json.get('password', None)
if username != 'test' or password != 'test':
return jsonify({'login': False}), 401
# Create the tokens we will be sending back to the user
access_token = create_access_token(identity=username)
refresh_token = create_refresh_token(identity=username)
# Set the JWT cookies in the response
resp = jsonify({'login': True})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
return resp, 200
I use flask_restx which automatically turns the response into JSON, so that jsonify in the first example is not needed. However, still still need to jsonify it, because i can not use set_access_cookie on a dictionary. This results at the end in a nested response like this jsonify(jsonify(x))
#api.route("/login")
class UserLogin(Resource):
def post(self):
"""Allows a new user to login with his email and password"""
email = request.get_json()["email"]
password = request.get_json()["password"]
user = User.query.filter_by(email=email).one_or_none()
if user is None:
return {"message": "user does not exist"}, 404
user = user.format()
if bcrypt.check_password_hash(pw_hash=user["password"], password=password):
if user["active"]:
resp = jsonify({"login": True})
access_token = create_access_token(identity=user)
refresh_token = create_refresh_token(user)
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
return resp, 200
# return (
# {"access_token": access_token, "refresh_token": refresh_token},
# 200,
# )
else:
return {"message": "User not activated"}, 400
else:
return {"message": "Wrong credentials"}, 401
This is the error: TypeError: Object of type Response is not JSON serializable
Any ideas how can I overcome this?
Was able to solve it like this:
data = dict(login=True)
resp = make_response(jsonify(**data), 200)
access_token = create_access_token(identity=user)
refresh_token = create_refresh_token(user)
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
return resp

Vimeo 'Replace' API Endpoint Not Changing Thumbnail

I am using Vimeo's API for the users of my app to upload videos, or replace their existing video with a new one. I am using a Vimeo Client to help me make the calls in my Django Application. Uploading works without any issues, but when I try to replace an existing video with a new one, the thumbnail stays as the old video. If you play the video, it will play the new one, but the thumbnail never changes.
Model Method that Uploads/Replaces
def vimeo_upload(self):
media_file = self.video_file
if media_file and os.path.exists(media_file.path):
v = vimeo.VimeoClient(token=settings.VIMEO_ACCESS_TOKEN, key=settings.VIMEO_API_KEY,
secret=settings.VIMEO_API_SECRET)
if self.video_url is None:
try:
video_uri = v.upload(media_file.path)
except AssertionError as exc:
logging.error('Vimeo Error: %s Video: %s' % (exc, media_file.path))
else:
self.video_url = video_uri
else:
try:
v.replace(video_uri=self.video_url, filename=media_file.path)
except Exception as exc:
self.video_url = None
logging.error('Vimeo Replace Error: %s Video: %s' % (exc, media_file.path))
# set the video title, description, etc.
if self.video_url:
try:
# convert locale from en-us form to en
v.patch(self.video_url, data={'description': self.customer.full_name, })
except Exception as exc:
logging.error('Vimeo Patch Error: %s Video: %s' % (exc, media_file.path))
Vimeo Client Model, and UploadVideoMixin
class UploadVideoMixin(object):
"""Handle uploading a new video to the Vimeo API."""
UPLOAD_ENDPOINT = '/me/videos'
REPLACE_ENDPOINT = '{video_uri}/files'
def upload(self, filename, upgrade_to_1080=False):
"""Upload the named file to Vimeo."""
ticket = self.post(
self.UPLOAD_ENDPOINT,
data={'type': 'streaming',
'upgrade_to_1080': 'true' if upgrade_to_1080 else 'false'},
params={'fields': 'upload_link,complete_uri'})
return self._perform_upload(filename, ticket)
def replace(self, video_uri, filename, upgrade_to_1080=False):
"""Replace the video at the given uri with the named source file."""
uri = self.REPLACE_ENDPOINT.format(video_uri=video_uri)
ticket = self.put(
uri,
data={'type': 'streaming',
'upgrade_to_1080': 'true' if upgrade_to_1080 else 'false'},
params={'fields': 'upload_link,complete_uri'})
return self._perform_upload(filename, ticket)
def _perform_upload(self, filename, ticket):
"""Take an upload ticket and perform the actual upload."""
if ticket.status_code != 201:
raise UploadTicketCreationFailure(ticket, "Failed to create an upload ticket")
ticket = ticket.json()
# Perform the actual upload.
target = ticket['upload_link']
last_byte = 0
# Try to get size of obj by path. If provided obj is not a file path
# find the size of file-like object.
try:
size = os.path.getsize(filename)
with io.open(filename, 'rb') as f:
while last_byte < size:
try:
self._make_pass(target, f, size, last_byte)
except requests.exceptions.Timeout:
# If there is a timeout here, we are okay with it, since
# we'll check and resume.
pass
last_byte = self._get_progress(target, size)
except TypeError:
size = len(filename.read())
f = filename
while last_byte < size:
try:
self._make_pass(target, f, size, last_byte)
except requests.exceptions.Timeout:
# If there is a timeout here, we are okay with it, since
# we'll check and resume.
pass
last_byte = self._get_progress(target, size)
# Perform the finalization and get the location.
finalized_resp = self.delete(ticket['complete_uri'])
if finalized_resp.status_code != 201:
raise VideoCreationFailure(finalized_resp, "Failed to create the video")
return finalized_resp.headers.get('Location', None)
def _get_progress(self, upload_target, filesize):
"""Test the completeness of the upload."""
progress_response = self.put(
upload_target,
headers={'Content-Range': 'bytes */*'})
range_recv = progress_response.headers.get('Range', None)
_, last_byte = range_recv.split('-')
return int(last_byte)
def _make_pass(self, upload_target, f, size, last_byte):
"""Make a pass at uploading.
This particular function may do many things. If this is a large upload
it may terminate without having completed the upload. This can also
occur if there are network issues or any other interruptions. These
can be recovered from by checking with the server to see how much it
has and resuming the connection.
"""
response = self.put(
upload_target,
timeout=None,
headers={
'Content-Length': str(size),
'Content-Range': 'bytes: %d-%d/%d' % (last_byte, size, size)
}, data=f)
if response.status_code != 200:
raise VideoUploadFailure(response, "Unexpected status code on upload")
class VimeoClient(ClientCredentialsMixin, AuthorizationCodeMixin, UploadMixin):
"""Client handle for the Vimeo API."""
API_ROOT = "https://api.vimeo.com"
HTTP_METHODS = set(('head', 'get', 'post', 'put', 'patch', 'options', 'delete'))
ACCEPT_HEADER = "application/vnd.vimeo.*;version=3.2"
USER_AGENT = "pyvimeo 0.3.10; (http://developer.vimeo.com/api/docs)"
def __init__(self, token=None, key=None, secret=None, *args, **kwargs):
"""Prep the handle with the authentication information."""
self.token = token
self.app_info = (key, secret)
self._requests_methods = dict()
# Make sure we have enough info to be useful.
assert token is not None or (key is not None and secret is not None)
# Internally we back this with an auth mechanism for Requests.
#property
def token(self):
return self._token.token
#token.setter
def token(self, value):
self._token = _BearerToken(value) if value else None
def __getattr__(self, name):
"""This is where we get the function for the verb that was just
requested.
From here we can apply the authentication information we have.
"""
if name not in self.HTTP_METHODS:
raise AttributeError("%r is not an HTTP method" % name)
# Get the Requests based function to use to preserve their defaults.
request_func = getattr(requests, name, None)
if request_func is None:
raise AttributeError(
"%r could not be found in the backing lib" % name
)
#wraps(request_func)
def caller(url, jsonify=True, **kwargs):
"""Hand off the call to Requests."""
headers = kwargs.get('headers', dict())
headers['Accept'] = self.ACCEPT_HEADER
headers['User-Agent'] = self.USER_AGENT
if jsonify \
and 'data' in kwargs \
and isinstance(kwargs['data'], (dict, list)):
kwargs['data'] = json.dumps(kwargs['data'])
headers['Content-Type'] = 'application/json'
kwargs['timeout'] = kwargs.get('timeout', (1, 30))
kwargs['auth'] = kwargs.get('auth', self._token)
kwargs['headers'] = headers
if not url[:4] == "http":
url = self.API_ROOT + url
response = request_func(url, **kwargs)
if response.status_code == 429:
raise APIRateLimitExceededFailure(
response, 'Too many API requests'
)
return response
return caller
class _BearerToken(requests.auth.AuthBase):
"""Model the bearer token and apply it to the request."""
def __init__(self, token):
self.token = token
def __call__(self, request):
request.headers['Authorization'] = 'Bearer ' + self.token
return request