I would like to play with the twitter API, but I'm lost with how access the API, get TimeLine, RT, etc, after login with django social auth.
Can anyone provide an example of another twitter library that I can use to access streaming, timeline, etc. after authenticating with Django social Auth?
I'm checking tweepy but I can't see how to use it if I don't need to use the tweepy auth method.
This example from the Django-social-auth docs shows what you need:
>>> from pprint import pprint
>>> from social_auth.models import UserSocialAuth
>>> instance = UserSocialAuth.objects.filter(provider='twitter').get(...)
>>> pprint(instance.tokens)
{u'oauth_token': u'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
u'_token_secret': u'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'}
The UserSocialAuth model will automatically store the access tokens you need. You access them via the tokens attribute.
Hope that helps.
You need to get the tokens from the UserSocialAuth instance associated to the user:
try:
instance = UserSocialAuth.objects.filter(user=request.user).get()
except ObjectDoesNotExist:
return redirect(getattr(settings,'LOGIN_URL','/login/twitter/'))
After retrieving the instance, get the keys:
oauth_access_token=(instance.tokens).get('oauth_token')
oauth_access_secret=(instance.tokens).get('oauth_token_secret')
With the token and secret, you can now connect to twitter using the package of your choice.
When a user grants your app access to Twitter, you'll get an access token & access token secret. Save it on your db. You use that to access the API.
Example is at: https://github.com/tweepy/tweepy/blob/master/examples/oauth.py
Related
Using:
Django 1.11
Python 3.6
DRF with JWT in FE
I understand that the Django admin uses a session, and basic authentication.
What I did so far: Replaced the Django Admin authentication signin page with AWS-Cognito:
The user goes to domain/admin/*, redirected to signin in AWS
On successful signin the user is redirected to the redirect_uri, leads to a Django View
In the view I replace the code with tokens
I can't navigate to any Admin page - I am trying to redirect, but that doesn't work since I didn't login() the User
Stuck - I would like to associate the User with the fetched tokens and authenticate with every Admin page request, and when the user logs out delete the tokens
What to do next?
When I use JWT with the Front End application, every request.META has HTTP_AUTHORIZATION, and uses a suitable backend.
I know how to add backends, and potentially leverage the user.backend (I also use Cognito-JWT for other FE portions, so already wrote BE for that)
I need to find a way to replace the Django Admin sessions authentication with the fetched token
Thank you!
EDIT:
If I login() the user, and set it to a model backend that I have already I can navigate to any admin page - but using the session that I created when I logged the user in.
I would like to have the user be set to a new model backend, with authentication that uses a token (from Django backend docs):
class MyBackend:
def authenticate(self, request, token=None):
# Check the token and return a user.
...
How do I make the different Admin pages requests pass the token to the authentication?
Where do I store the token? (I could make a NewUserModel that is 1-1 with the Django User model, and place a token field there)
I am thinking of writing a middleware to capture all requests, and looking into the target URL - if Admin url, add the token to the HTTP_AUTHORIZATION once I fetch the user mentioned in #2 (the user is in every request due to DRF)
EDIT 2
My solution is getting more and more like this stack solution, I would have liked to know if there are any other options, but here is what I did so far:
I made a model that has a 1-1 user field, and a tokens field
As I am fetching/creating the user, I am also saving the tokens on the user's related model from #1 above
I created a middleware that is capturing any request in process_request, and has access to the user. I can see the tokens there as I access the user's related model from #1 above.
I am trying to set the HTTP_AUTHORIZATION header on the request, but cannot do that yet (currently stuck here)
In my backend, I am looking at the incoming request, and trying to fetch the HTTP_AUTHORIZATION - not there yet.
EDIT 3
I ended up just using the Django session as is - once the user authenticates with AWS-Cognito once, it is safe to assume that it is a legitimate User.
Then I just dump the Cognito-JWT, and login() the User.
Note: I am still interested in a solution that would drop the Django session for using the Cognito-JWT, and would love to hear suggestions.
I'm new learning graphene with django, and as the documentation says, I have this class:
import graphql_jwt
class Mutations(graphene.ObjectType):
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()
but calling the tockenAuth mutation, even when the token is correcty generates because the user and password are correct, I don't see anything saved in the session table:
Session.objects.all()
is always empty
I'm checking the session for login out any user. So, how can I generate the Session entry from the authToken mutation call and what's the correct/better way to login/logout users using graphql_jwt?
Regards
JWT is an alternative to sessions - it is another way to authenticate a request so you do not need sessions if you use JWT.
JWT also does not create any kind of information in database - you can just use cryptography to verify that the token is legitimate. To authenticate with JWT include JSONWebTokenBackend in your AUTHENTICATION_BACKENDS as described here.
Read more about jwt here.
I want to migrate flask_dance with my application to make the user authorize using google and another social networks.
I am getting this error:
Cannot get OAuth token without an associated user
Before i do the connection between the blueprint and sqlalchemy backend, the application worked just fine, if i removed the google_blueprint.backend line the error disappear.
Here is my __init__.py:
import os
from flask import Flask, redirect, url_for, current_app
from flask_login import current_user
from develop.models import (
db,
User,
OAuth
)
from flask_dance.contrib.google import make_google_blueprint
from flask_dance.consumer.backend.sqla import SQLAlchemyBackend
from flask_dance.consumer import oauth_authorized
from sqlalchemy.orm.exc import NoResultFound
def create_app(config_object):
app = Flask(__name__)
app.config.from_object(config_object)
db.init_app(app)
login_manager.init_app(app)
google_blueprint = make_google_blueprint(
client_id=app.config['GOOGLE_CLIENT_ID'],
client_secret=app.config['GOOGLE_CLIENT_SECRET'],
scope=["profile", "email"]
)
app.register_blueprint(google_blueprint, url_prefix='/login')
#oauth_authorized.connect_via(google_blueprint)
def google_logged_in(blueprint, token):
resp = blueprint.session.get("/oauth2/v2/userinfo")
if resp.ok:
account_info_json = resp.json()
email = account_info_json['email']
query = User.query.filter_by(email=email)
try:
user = query.one()
except NoResultFound:
user = User()
user.image = account_info_json['picture']
user.fullname = account_info_json['name']
user.username = account_info_json['given_name']
user.email = account_info_json['email']
db.session.add(user)
db.session.commit()
login_user(get_user, remember=True)
identity_changed.send(
current_app._get_current_object(),
identity=Identity(get_user.id)
)
#login_manager.user_loader
def load_user(userid):
return User.query.get(userid)
google_blueprint.backend = SQLAlchemyBackend(OAuth, db.session, user=current_user)
return app
Here is also my tables how i organized them in models.py:
class User(db.Model, UserMixin):
id = db.Column(db.Integer(), primary_key=True)
image = db.Column(db.String(), nullable=True)
fullname = db.Column(db.String())
username = db.Column(db.String(), unique=True)
password = db.Column(db.String())
email = db.Column(db.String(), unique=True)
class OAuth(OAuthConsumerMixin, db.Model):
user_id = db.Column(db.Integer(), db.ForeignKey(User.id))
user = db.relationship(User)
Please any help would be appreciated :)
TL;DR: You can disable this exception by setting user_required=False on the SQLAlchemyStorage object. However, the exception is being raised for a reason, and if you simply disable it like this, your database may get into an unexpected state where some OAuth tokens are not linked to users. There's a better way to solve this problem. Read on for details.
I am the author of Flask-Dance. This Cannot get OAuth token without an associated user exception is only present in version 0.13.0 and above of Flask-Dance. (CHANGELOG is here.) The pull request introducing this change has some more context for why the change was made.
There are several different ways to use OAuth. Here are some example use cases, all of which Flask-Dance supports:
I want to build a bot that can connect to one specific service, such as a Twitter bot that tweets to a specific account, or a Slack bot that connects to a specific Slack team. I want this bot to respond to HTTP requests, so it has to run as a website, even though I don't expect people to actually use this website directly.
I want to build a website where users can log in. Users need to create an account on my website using a username and password. After they have created an account, users may decide to link their account to other OAuth providers, like Google or Facebook, to unlock additional functionality.
I want to build a website where users can log in. Users should be able to create their account simply by logging in with GitHub (or any other OAuth provider). Users should not need to create a new password for my website.
Use case 1 is the simplest: do not pass a user or user_id argument to your SQLAlchemyStorage, and it will assume that your application does not use multiple user accounts. This means that your website can only link to one particular account on the remote service: only one Twitter account, only one Slack team, etc.
Use case 2 is also pretty simple: pass a user or user_id argument to your SQLAlchemyStorage. Flask-Dance will save the OAuth token into your database automatically, and link it to the user that is currently logged in.
Use case 3 is more complex, since it involves automatically creating both the OAuth token and the local user account at the same time. Different applications have different requirements for creating user accounts, and there's no way for Flask-Dance to know what those requirements are. As a result, Flask-Dance cannot handle this use case automatically. You must hook into the oauth_authorized signal, create the user account and associate it with the OAuth token manually, and return False to tell Flask-Dance to not attempt to handle the OAuth token automatically.
Before version 0.13.0, it was possible to accidentally create OAuth tokens in the database that were not linked with any users at all. In use case 3, the OAuth token is created before a local user account exists for that user, so Flask-Dance would save the OAuth token to the database without any linked local user account. You could use the oauth_authorized handler to associate the OAuth token with a local user account afterwards, but if your code is buggy and raises an exception, then the OAuth token could remain in your database, forever unlinked to any users.
Starting in version 0.13.0, Flask-Dance detects this problem and raises an exception, instead of saving an OAuth token to your database without an associated local user account. There are two ways to resolve this problem:
Rewrite your code to manually create the user account and associate it with the OAuth token. The documentation contains some example code you can use for this.
Disable this check, and tell Flask-Dance that it's OK to create OAuth tokens without associated users. You can disable this check by setting user_required=False on the SQLAlchemyStorage object.
I believe that option 1 is the better solution by far, but it requires more understanding of what Flask-Dance is actually doing behind the scenes. I've written some documentation that describes how to handle multi-user setups, which discusses this problem as well.
Is it possible to use Django JWT rest framework to create a password recovery link?
An example would be to recover password by email and create an access token for it.
Or do I need to use the features of Django admin to do this?
Thank you very much.
This is not something you can do in Django JWT REST framework alone. You need to write custom views to fulfil this behavior.
You can subclass auth.PasswordResetView and create a new JWT token manually that is used in a password reset link delivered to email address of active user.
The following example is given in django-rest-framework-jwt for creating JWT token manually.
# Source: https://jpadilla.github.io/django-rest-framework-jwt/#creating-a-new-token-manually
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
You'll also need to subclass auth.PasswordResetConfirmView to verify that the token wasn't used/expired.
Another option is to use Djoser.
This library would allow you to configure a password reset endpoint, user creation, password change, configure the email, etc. It is also compatible with JWT.
I've been asked to provide a "Login with Facebook" functionality to an iOS app I am creating.
The app connects to a REST api created with Piston, the web application is created with Django and uses social_auth. The application also has a Facebook login.
My thought was to create a service 'FBLogin' providing just the Facebook profile UID (separate FB login procedure on iPhone to get the ID). Using the SocialAuth models I can query the DB with uid and provider to fetch the user... but how can i use the authentication mechanism to get this user instance authenticated?
Any ideas on getting this right?
This just doesn't feel good ... getting the user instance authenticated is a pain...
The username password authentication is already implemented ... without a problem.
Btw, don't have django experience ... do have a lot of other development experience so understanding python and django isn't that hard :)
Tx
Y
It doesn't really seem to be documented anywhere, but you can do this in your REST handler:
from social_auth.backends.pipeline.social import associate_user
from social_auth.backends.facebook import FacebookBackend
from social_auth.models import UserSocialAuth
myextra_data = {
'access_token' : 'jfkdlfsdgeyejfghfdsjdfpoweipuo',
'id' : 123456789,
}
usa, created = UserSocialAuth.objects.get_or_create(provider = 'facebook',
uid=123456789)
usa.user = user
usa.extra_data = myextra_data
usa.save()
if created:
associate_user(backend=FacebookBackend, user=user, uid=usa.uid)
These get pretty vendor-specific in terms of how data gets formatted in extra_data so YMMV