[PYTHON] Twitter authentication using Flask and React is very forcible using WebSocket

Overview

There are multiple people who authenticate with react on the following pages. React Authentication with Twitter, Google, Facebook and Github Create a SPA with React and log in with Twitter authentication (OAuth). The back end is Rails However, I was stupid, so I wasn't sure about it (later, I couldn't find flask on the server side of express or Rails on the above page). Therefore, I wrote a very aggressive certification with a small hand.

It's my first time to use WebSocket, React's useEffect, and Flask, so it would be nice if you could see it for reference (I'd like to rewrite it with proper code later).

flow

This time, when you press the "Linked App Authentication" button, the link will start, so please change that part appropriately.

  1. Press the button to authenticate (handleClick function in js)
  2. The string "Twitter" jumps to the server (handleClick function in js)
  3. The server returns the URL (for Twitter authentication) (pipe function in python)
  4. Move by URL with js (ws.onmessage in js = in function (e))
  5. Twitter authentication screen
  6. Authenticate
  7. redirect to client side page
  8. Information on auth_token and auth_verifier goes to the server (from ws.onopen in useEffect)
  9. The server creates an access_token_secret using token and verifier (user_timeline in python)
  10. Bring the latest timeline of the authenticated user from Twitter (user_timeline in python)

Tweepy is used for authentication.

Actual code

index.py


import os
import json
import sys
import tweepy
from flask import Flask, session, redirect, render_template, request, jsonify, abort, make_response
from flask_cors import CORS, cross_origin
from os.path import join, dirname
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler

app = Flask(__name__)
CORS(app)
#Decide on your own
app.secret_key = ""
#Bring from Twitter App
CONSUMER_KEY = ""
CONSUMER_SECRET = ""

@app.route('/pipe')
def pipe():
   if request.environ.get('wsgi.websocket'):
       ws = request.environ['wsgi.websocket']
       while True:
            message = ws.receive()
            # print(message)
            #When you press the button, Twitter will be sent by websocket, so it will ignite if sent
            if message == "Twitter":
                auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
                try:
                    #Get URL for linked app authentication
                    redirect_url = auth.get_authorization_url()
                    session['request_token'] = auth.request_token
                except Exception as ee:
                    # except tweepy.TweepError:
                    sys.stderr.write("*** error *** twitter_auth ***\n")
                    sys.stderr.write(str(ee) + "\n")
                #Send back url with websocket
                ws.send(redirect_url)
                ws.close()
                #If there is no return, an error will occur
                return redirect_url
            elif message != None:
                messages = json.loads(message)
                # print(messages)
                user_timeline(messages, ws)
def user_timeline(auths, ws):
    #Authenticate your app with tweepy
    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    verifier = str(auths["oauth_verifier"])
    # Access token,Get Access token secret.
    auth.request_token['oauth_token'] = str(auths["oauth_token"])
    auth.request_token['oauth_token_secret'] = verifier
    try:
        access_token_secret = auth.get_access_token(verifier)
    except Exception as ee:
        print(ee)
        return ""

    print(access_token_secret)
    #Access the Twitter API with tweepy
    api = tweepy.API(auth)

    #Gets and returns a list of tweets in user's timeline
    for status in api.user_timeline(count=1):
        text = status.text
    #Gets and returns a list of tweets in user's timeline
    ws.send(text)
    ws.close()

def main():
    app.debug = True
    server = pywsgi.WSGIServer(("", 5000), app, handler_class=WebSocketHandler)
    server.serve_forever()

if __name__ == "__main__":
    main()

app.js


import React from 'react';
import './App.css';
import { useState, useEffect } from 'react';

function App() {
  const [flag, setFlag] = useState(false);
  const [userData, setUserData] = useState('');
  const [data, setData] = useState('');
  //Communication with webSocket
  const ws = new WebSocket('ws://localhost:5000/pipe');
  //Returns the verifier in the url after ws opens before rendering
  useEffect(() => {
    ws.onopen = event => {
      if (userData == false && window.location.search.includes('verifier')) {
        setFlag(true);
        ws.send(getParam('oauth_verifier'));
      }
    };
    setUserData('true');
  });

  //Code to bring a specific element in the url
  function getParam(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, '\\$&');
    var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
      results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, ' '));
  }

  //Receives when a message is sent from the server side and activates the function(To jump to the Twitter authentication URL)
  ws.onmessage = e => {
    console.log(e);
    if (e.data.includes('oauth_token')) {
      window.location.href = e.data;
    } else {
      console.log(e);
      setData(e.data);
    }
  };
  //When clicked(This time, if you click the button on the character, Twitter will be sent to the server)
  function handleClick() {
    console.log('rest');
    ws.send('Twitter');
  }
  console.log(flag);

  //Switching render elements
  let render = flag ? (
    <div>{data}</div>
  ) : (
    <button onClick={handleClick}>Linked app authentication</button>
  );
  return <>{render}</>;
}

export default App;

To be honest, it's a very appropriate code, so I think it's just right if you can refer to it (** After that, a websocket error will occur. I think that it is because communication is done in the closed state, so I will edit it if I can fix it **)

Recommended Posts

Twitter authentication using Flask and React is very forcible using WebSocket
React and Flask to GCP
Authentication using tweepy-User authentication and application authentication (Python)
Basic authentication and Digest authentication with Flask
I want to make a web application using React and Python flask
I tried using Twitter api and Line api
Face image inference using Flask and TensorFlow