Flask and React - Handling tokens after Spotify Authorization - reactjs

I have implemented JWT for user login in my app (before Spotify Auth), like so:
Flask
#auth_blueprint.route('/auth/login', methods=['POST'])
def login_user():
# get post data
post_data = request.get_json()
response_object = {
'status': 'fail',
'message': 'Invalid payload.'
}
if not post_data:
return jsonify(response_object), 400
email = post_data.get('email')
password = post_data.get('password')
try:
# fetch the user data
user = User.query.filter_by(email=email).first()
if user and bcrypt.check_password_hash(user.password, password):
auth_token = user.encode_auth_token(user.id)
if auth_token:
response_object['status'] = 'success'
response_object['message'] = 'Successfully logged in.'
response_object['auth_token'] = auth_token.decode()
return jsonify(response_object), 200
else:
response_object['message'] = 'User does not exist.'
return jsonify(response_object), 404
except Exception:
response_object['message'] = 'Try again.'
return jsonify(response_object), 500
These are the methods of my SQLAlchemy User(db.Model)
def encode_auth_token(self, user_id):
"""Generates the auth token"""
try:
payload = {
'exp': datetime.datetime.utcnow() + datetime.timedelta(
days=current_app.config.get('TOKEN_EXPIRATION_DAYS'),
seconds=current_app.config.get('TOKEN_EXPIRATION_SECONDS')
),
'iat': datetime.datetime.utcnow(),
'sub': user_id
}
return jwt.encode(
payload,
current_app.config.get('SECRET_KEY'),
algorithm='HS256'
)
except Exception as e:
return e
#staticmethod
def decode_auth_token(auth_token):
"""
Decodes the auth token - :param auth_token: - :return: integer|string
"""
try:
payload = jwt.decode(
auth_token, current_app.config.get('SECRET_KEY'))
return payload['sub']
except jwt.ExpiredSignatureError:
return 'Signature expired. Please log in again.'
except jwt.InvalidTokenError:
return 'Invalid token. Please log in again.'
React
App.jsx
loginUser(token) {
window.localStorage.setItem('authToken', token);
this.setState({ isAuthenticated: true });
this.getUsers();
this.createMessage('Welcome', 'success');
};
(...)
<Route exact path='/login' render={() => (
<Form
isAuthenticated={this.state.isAuthenticated}
loginUser={this.loginUser}
/>
)} />
and
Form.jsx
handleUserFormSubmit(event) {
event.preventDefault();
const data = {
email: this.state.formData.email,
password: this.state.formData.password
};
const url = `${process.env.REACT_APP_WEB_SERVICE_URL}/auth/${formType.toLowerCase()}`;
axios.post(url, data)
.then((res) => {
this.props.loginUser(res.data.auth_token);
})
Third Party Authorization + Second App Authentication
Now I'd like to add a second layer of authentication and handle tokens after Spotify callback, like so:
#spotify_auth_bp.route("/callback", methods=['GET', 'POST'])
def spotify_callback():
# Auth Step 4: Requests refresh and access tokens
SPOTIFY_TOKEN_URL = "https://accounts.spotify.com/api/token"
CLIENT_ID = os.environ.get('SPOTIPY_CLIENT_ID')
CLIENT_SECRET = os.environ.get('SPOTIPY_CLIENT_SECRET')
REDIRECT_URI = os.environ.get('SPOTIPY_REDIRECT_URI')
auth_token = request.args['code']
code_payload = {
"grant_type": "authorization_code",
"code": auth_token,
"redirect_uri": REDIRECT_URI,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
}
post_request = requests.post(SPOTIFY_TOKEN_URL, data=code_payload)
# Auth Step 5: Tokens are Returned to Application
response_data = json.loads(post_request.text)
access_token = response_data["access_token"]
refresh_token = response_data["refresh_token"]
token_type = response_data["token_type"]
expires_in = response_data["expires_in"]
# At this point, there is to generate a custom token for the frontend
# Either a self-contained signed JWT or a random token?
# In case the token is not a JWT, it should be stored in the session (in case of a stateful API)
# or in the database (in case of a stateless API)
# In case of a JWT, the authenticity can be tested by the backend with the signature so it doesn't need to be stored at all?
res = make_response(redirect('http://localhost/about', code=302))
return res
Note: this a possible endpoint for getting new Spotify tokens:
#spotify_auth_bp.route("/refresh_token", methods=['GET', 'POST'])
def refresh_token():
SPOTIFY_TOKEN_URL = "https://accounts.spotify.com/api/token"
CLIENT_ID = os.environ.get('SPOTIPY_CLIENT_ID')
CLIENT_SECRET = os.environ.get('SPOTIPY_CLIENT_SECRET')
code_payload = {
"grant_type": "refresh_token",
"refresh_token": refresh_token,
}
encode = 'application/x-www-form-urlencoded'
auth = base64.b64encode("{}:{}".format(CLIENT_ID, CLIENT_SECRET).encode())
headers = {"Content-Type" : encode, "Authorization" : "Basic {}".format(auth)}
post_request = requests.post(SPOTIFY_TOKEN_URL, data=code_payload, headers=headers)
response_data = json.loads(post_request.text)
access_token = response_data["access_token"]
refresh_token = response_data["refresh_token"]
token_type = response_data["token_type"]
expires_in = response_data["expires_in"]
return access_token
What is the best way of handling my tokens after Spotify callback?
Considering that, once user is logged with the app, he will also be logged with Spotify non-stop, having to refresh Spotify's access token every 60 minutes:
Is Authorization Code a server-to-server flow only to protect secret app credentials, and then it is safe to have tokens at frontend?
Should I keep both Access token and refresh tokens stored at frontend, and have a Stateless JWT?
Should I keep only temporary access token and keep refresh tokens at database, having a Stateful JWT?
Should I opt for a Session, persisted only server-side, instead?
What is the safest way of handling my sensitive data here? And, considering the code above, how so?

A huge number of questions here! Let's take them one by one:
Is Authorization Code a server-to-server flow only to protect secret app credentials, and then it is safe to have tokens at frontend?
In the Authorization Code grant, you have to exchange the Authorization Code for a token. This is done with a request to /token (grant_type: authorization_code) and it requires your client_id and client_secret which is secretly stored in your server (aka not-public in your react web app). In this context it's indeed server-to-server.
Should I keep both Access token and refresh tokens stored at frontend, and have a Stateless JWT?
In your case, I would say no. If the token will be used to do some API request to Spotify on server-side, please keep access_token and refresh_token server-side.
But then, it's not anymore stateless ? Indeed.
What could you do "stateless" ?
If you really want/need stateless tokens, IMHO you could store the access_token in a Cookie with following options (and it's mandatory):
Secure: cookies only sent on HTTPS
HttpOnly: not accessible from Javascript
SameSite: preferrably strict! (here it depends if you need CORS)
PRO:
It's stateless
CON:
It might be a huge cookie.
Anyone which access your computer can get the access_token, just like a session cookie. Expiration time is important here. See also: https://stackoverflow.com/a/41076836/2437450
Something else ???? To be challenged.
The case of refresh_token.
I would recommend to store refresh tokens server-side because it's usually a long-life token.
What to do when the access_token expire ?
When a request comes with an expired access_token, you can simply refresh the access_token with server-side-stored refresh_token, do the job, and return the response with a new access_token stored through Set-Cookie header.
Additional note about JWT
If you always have JWT and you store them in Http-Only cookies, you'll probably say that you don't have any way to know if your are logged-in from your React app.
Well there is a trick I already experimented with JWT which is pretty nice.
A JWT is composed of 3 parts; the header, the payload and the signature. What you actually want to protect in your cookies is the signature. Indeed, if you don't have the right signature the JWT is useless. So what you could do is to split the JWT and make only the signature Http-Only.
In your case it should look like:
#app.route('/callback')
def callback():
# (...)
access_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiIsIm5hbWUiOiJSYXBoYWVsIE1lZGFlciJ9.V5exVQ92sZRwRxKeOFxqb4DzWaMTnKu-VmhW-r1pg8E'
a11n_h, a11n_d, a11n_s = access_token.split('.')
response = redirect('http://localhost/about', 302)
response.set_cookie('a11n.h', a11n_h, secure=True)
response.set_cookie('a11n.d', a11n_d, secure=True)
response.set_cookie('a11n.s', a11n_s, secure=True, httponly=True)
return response
You would have 3 cookies:
a11n.h: the header (options: Secure)
a11n.d: the payload (options: Secure)
a11n.s: the signature (options: Secure, Http-Only)
The consequence is:
a11n.d cookie is accessible from your React app (you can even get userinfo from it)
a11n.s cookie is not accessible from Javascript
You have to reassemble the access_token from cookies on server-side before sending request to Spotify
To reassemble the access_token:
#app.route('/resource')
def resource():
a11n_h = request.cookies.get('a11n.h')
a11n_d = request.cookies.get('a11n.d')
a11n_s = request.cookies.get('a11n.s')
access_token = a11n_h + '.' + a11n_d + '.' + a11n_s
jwt.decode(access_token, verify=True)
I hope it helps!
Disclaimer:
Code samples need to be improved (error handling, checks, etc). They are only examples to illustrate the flow.

Related

Dotnet API requires auth both for application and React

I must be really stupid, But I have been struggling for weeks to try solve this issue, and all the digging I have done (in Stack overflow and MS Documentation) has yielded no results (or I'm too stupid to implement auth correctly)
I have a dotnet service which needs to act as an API - both for an application to post data to (an exe which logs exception data), and for a UI (react app) to get the posted exceptions
the exe can successfully send data to the dotnet app after first getting a token from login.microsoftonline.com and then sending the token (and secret) in the http request.
A sample postman pre-request script of the auth used (I've set all the secret stuff as environment variables):
pm.sendRequest({
url: 'https://login.microsoftonline.com/' + pm.environment.get("tenantId") + '/oauth2/v2.0/token',
method: 'POST',
header: 'Content-Type: application/x-www-form-urlencoded',
body: {
mode: 'urlencoded',
urlencoded: [
{key: "grant_type", value: "client_credentials", disabled: false},
{key: "client_id", value: pm.environment.get("clientId"), disabled: false},
{key: "client_secret", value: pm.environment.get("clientSecret"), disabled: false}, //if I don't configure a secret, and omit this, the requests fail (Azure Integration Assistant recommends that you do not configure credentials/secrets, but does not provide clear documentation as to why, or how to use a daemon api without it)
{key: "scope", value: pm.environment.get("scope"), disabled: false}
]
}
}, function (err, res) {
const token = 'Bearer ' + res.json().access_token;
pm.request.headers.add(token, "Authorization");
});
Now in React, I am using MSAL(#azure/msal-browser) in order to login a user, get their token, and pass the token to one of the dotnet endpoints using axios as my http wrapper, but no matter what I do, it returns http status 401 with WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid".
A simplified code flow to login user and request data from the API:
import {publicClientApplication} from "../../components/Auth/Microsoft";//a preconfigured instance of PublicClientApplication from #azure/msal-browser
const data = await publicClientApplication.loginPopup();
// ... some data validation
publicClientApplication.setActiveAccount(data.account);
// .. some time and other processes may happen here so we don't access token directly from loginPopup()
const activeAccout = publicClientApplication.getActiveAccount();
const token = publicClientApplication.acquireTokenSilent(activeAccount).accessToken;
const endpointData = await api()/*an instance of Axios.create() with some pre-configuration*/.get(
'/endpoint',
{ headers: {'Authorization': `bearer ${token}`} }); // returns status 401
The dotnet service has the following configurations
public void ConfigureServices(IServiceCollection services){
...
var authScheme = services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme);
authScheme.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
...
}
namespace Controllers{
public class EndpointController : ControllerBase{
...
[Authorize]
[HttpGet]
public IActionResult GetEndpoint(){
return Ok("you finally got through");
}
}
}
I've literally tried so many things that I've lost track of what I've done...
I've even cried myself to sleep over this - but that yielded no results
i can confirm that running the request in postman, with the pre request script, it is possible to get the response from the endpoint
So....
After much digging and A-B Testing I was able to solve this issue.
I discovered that I was not sending the API scope to the OAuth token endpoint. To do this I needed to change the input for acquireTokenSilent.
The updated code flow to login user and request data from the API:
import {publicClientApplication} from "../../components/Auth/Microsoft";//a preconfigured instance of PublicClientApplication from #azure/msal-browser
const data = await publicClientApplication.loginPopup();
// ... some data validation
publicClientApplication.setActiveAccount(data.account);
// .. some time and other processes may happen here so we don't access token directly from loginPopup()
const activeAccout = publicClientApplication.getActiveAccount();
const token = publicClientApplication.acquireTokenSilent({scopes:["api://XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/.default"],account:activeAccount}).accessToken;//here scopes is an array of strings, Where I used the api URI , but you could directly use a scope name like User.Read if you had it configured
const endpointData = await api()/*an instance of Axios.create() with some pre-configuration*/.get(
'/endpoint',
{ headers: {'Authorization': `bearer ${token}`} }); // returns status 401

Within a React app, what is the correct way to query an API that requires an Oauth token

Ebay is closing its Finding API and my React application needs to move to the Browse API https://developer.ebay.com/api-docs/buy/browse/overview.html and I need to use Oauth. My app does not require a user to authenticate with Ebay, it just shows the ebay auctions that are relevant to the page they are looking at. Within my Ebay developer account I have an application that provides an App ID (Client ID) and Cert ID (Client Secret), however I just cannot figure out how to manage the refresh token request and the application token request so that I can actually send a request to the Browse API.
My question is: within a React application, what is the correct way to use oauth refresh and authorisation tokens, and use them to successfully make a request to an Oauth protected endpoint (in this case Ebay’s)?
I have an Ebay React component (shown at the bottom of this question) and I’ve ‘borrowed’ much of this from How to get access_token using refresh token from Ebay?
However in that question const refreshToken = 'xxxxxxxx'; is mentioned and I can’t figure out how to get one. Ebay has documentation on using a refresh token https://developer.ebay.com/api-docs/static/oauth-refresh-token-request.html which says:
Configuring the request payload
Format the payload of your POST request with the following values:
- Set grant_type to refresh_token.
- Set refresh_token to the refresh token value returned from the authorization code grant request.
So this looks as though I get the refresh token in a response to an authorisation request which seems to be documented at https://developer.ebay.com/api-docs/static/oauth-client-credentials-grant.html for applications such as mine (not users). Following this example I can make a cURL request
curl -X POST 'https://api.ebay.com/identity/v1/oauth2/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Authorization: Basic U3DFSDF888888D00000000000000=' \ //not the real details
-d 'grant_type=client_credentials&scope=https%3A%2F% 2Fapi.ebay.com%2Foauth%2Fapi_scope'
-u 'StuartBrr-PRD-cd00000-0000000:PRD-0000-00000-0000-000-000' //not the real details
Which returns
{"access_token":"v^1.1#i^1#p^1#I^3#r^0#f^0#t^H4sI……","expires_in":7200,"token_type":"Application Access Token"}%
But there is no mention of a refresh token. So I suppose I could run a request against the API using that token, but it would only work until the refresh token expired.
If I run
curl 'https://api.ebay.com/identity/v1/oauth2/token'
-d 'grant_type=refresh_token&scope=https%3A%2F% 2Fapi.ebay.com%2Foauth%2Fapi_scope'
-u 'StuartBrr-PRD-cd00000-0000000:PRD-0000-00000-0000-000-000'
I get a response {"error":"invalid_grant","error_description":"the provided authorization refresh token is invalid or was issued to another client"}%
If I run my React application including the below component I can see a preflight request which is successful, and another request which reports a CORS error.
The request with the CORS error is passing the below headers in the payload
So I can’t even get the response which only gives me the Application Access Token, let alone make a subsequent call to the Ebay Browse API
Any guidance very much appreciated!
Below if the React component I have that attempts to get the token and I would like to make the API request
import React from "react";
import axios from "axios";
import queryString from 'query-string';
class Ebay extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
results: true,
error: "",
data: [],
};
}
componentDidMount() {
//Prod
const appID = 'StuartBrr-PRD-cd00000-0000000; // these are obviously not the real details
const certID = 'PRD-0000-00000-0000-000-000;
const URL = 'https://api.ebay.com/identity/v1/oauth2/token';
//sandbox
// const appID = 'StuartBr-STr-SBX-b0000000-00000000';
// const certID = 'SBX-0000000-00000-000-0000-0000;
// const URL = 'https://api.sandbox.ebay.com/identity/v1/oauth2/token';
const token = Buffer.from(`${appID}:${certID}`);
const scopes = [
'https://api.ebay.com/oauth/api_scope'
]
const { data } = axios.post(URL, {
'headers': {
'Authorization': `Basic ${token.toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
})
console.log("HERE IS AXOIS DATA "+ JSON.stringify(data));
}
render() {
console.log("IN EBAY COMPONENT");
// Render results in a table
}
}
export default Ebay;
You have to setup auth_accepted_url in developer account first,
then call
https://auth.ebay.com/oauth2/authorize with all parameters
in this way, after authentication, in auth_accepted_url
you will receive, together with auth_token, the refresh_token with its lifespan.
eBay documentation is not very clear so it requires you to read it twice.

HTTP method’s error: 401 (Unauthorized) on React & Django(DRF)

I completed manipulating authentication with token by referring this article, and then I’m trying to create a crud function such creating post, displaying posts, etc… . However, I have an error when I fetched the url which displays posts(IE, fetching url I defined as “index” method on views.py of app for auth manipulation), I have 401 error even though I can access by using url of the backend without any error even on terminal.
I found some config codes which are related to authentication and permission for manipulation of authentication with token on settings.py causes this error, since when I delete these codes, the crud function works. But obviously authentication function no longer works (index method on views.py retrieve only token, another informations are filled blank) by this solution.
//fetch method on frontend
try{
const res = await fetch(`${base_url}/accounts/current_user/`,{
method:'GET',
headers:{
Authorization:`JWT ${localStorage.getItem('token')}`
}
})
const data = await res.json();
setUsername(data.username);
console.log(data)
}catch(err){console.log(err)};
//fetch posts on frontend
const getProblems = async() =>{
const res = await fetch(base_url+'/problems/index');
const data = await res.json();
setProblems(data);
}
//views.py on app for auth manipulation
#api_view(['GET'])
def get_current_user(request):
serializer = GetFullUserSerializer(request.user)
print(serializer.data)
return Response(serializer.data)
//settings.py(related to auth, cors):
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
)
}
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000',
)
CORS_ALLOW_CREDENTIALS = True
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER':
'new_sns.utils.custom_jwt_response_handler',
}
I have another files such serializer.py, urls.py,but they are absolutely same as the article I extracted.
I guess I misunderstand something around configuration. I would like to hear some of suggestions. Please let me know if you think if there may be problems on another files which I didn't attach on here.
Thanks.
Try changing JWT ${localStorage.getItem('token')} to Authorization:`Bearer ${localStorage.getItem('token')}.
In case this won't work, try djangorestframework-simplejwt - package recommended on DRF's docs.
JSON Web Token is a fairly new standard which can be used for
token-based authentication. Unlike the built-in TokenAuthentication
scheme, JWT Authentication doesn't need to use a database to validate
a token. A package for JWT authentication is
djangorestframework-simplejwt which provides some features as well as
a pluggable token blacklist app.
django-api-logger and axios-jwt may also come handy.

How do I manage an access token, when storing in local storage is not an option?

I have a ReactJS app running in browser, which needs access to my backend laravel-passport API server. So, I am in control of all code on both client and server side, and can change it as I please.
In my react app, the user logs in with their username and password, and if this is successful, the app recieves a personal access token which grants access to the users data. If I store this token in local storage, the app can now access this users data by appending the token to outgoing requests.
But I do not want to save the access token in local storage, since this is not secure. How do I do this?
Here is what I have tried:
In the laravel passport documentation, there is a guide on how to automatically store the access token in a cookie. I believe this requires the app to be on the same origin, but I cannot get this to work. When testing locally, I run the app on localhost:4000, but the API is run on my-app.localhost. Could this be a reason why laravel passport does not make a cookie with the token, although they technically both have origin localhost?
OAuth has a page on where to store tokens. I tried the three options for "If backend is present", but they seem to focus on how the authorization flow rather than how to specifically store the token.
Here's the relevant parts of my code (of course, feel free to ask for more if needed):
From my react app:
const tokenData = await axios.post(this.props.backendUrl + '/api/loginToken', { email: 'myEmail', password: 'myPassword' })
console.log('token data: ', tokenData)
const personalAccessToken = tokenData.data.success.token;
var config = {
headers: {
'Authorization': "Bearer " + personalAccessToken
};
const user = await axios.get(this.props.backendUrl + '/api/user', config);
From the controller class ApiController:
public function loginToken()
{
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')->accessToken;
return response()->json(['success' => $success], 200);
} else {
return response()->json(['error' => 'Unauthorised'], 401);
}
}
and the loginToken function is called from the /api/loginToken route.
Expected and actual results:
Ideally, I would love to have the token saved in a cookie like in the passport documentation, so I don't even have to attach the token to outgoing requests from the react app, but I'm not sure that this is even possible. Perhaps with third party cookies?
Else, I'd just like to find some way to store the token securely (for example in a cookie?), and then append it to outgoing calls from the react app.

Salesforce cometD: 401::Request requires authentication

I have to subscribe to cometD Salesforce channel and hence building cometD client in python. I am using the below python library.
https://github.com/dkmadigan/python-bayeux-client
And below is the handshake response I am getting
{'Host': ['xxxxx.my.salesforce.com/cometd/42.0/'], 'Content-Type': ['application/x-www-form-urlencoded'], 'Authorization': ['admin#123Pi6s9Y2QVergfergregpqqY']} message={"channel":"/meta/handshake","id":"1",
"supportedConnectionTypes":["callback-polling", "long-polling"],
"version":"1.0","minimumVersion":"1.0"} Headers({'host': ['xxxxx.my.salesforce.com/cometd/42.0/'], 'content-type': ['application/x-www-form-urlencoded'], 'authorization': ['admin#123Pi6s9Y2QVergfergregpqqY']}) {u'successful': False, u'advice': {u'reconnect': u'none'}, u'ext': {u'replay': True, u'sfdc': {u'failureReason': u'401::Request requires authentication'}, u'payload.format': True}, u'error': u'403::Handshake denied', u'id': u'1', u'channel': u'/meta/handshake'}
And I am getting 401::Request requires authentication.
In the Authorization key, I have concatenated password and Access token i.e. admin#123Pi6s9Y2QVergfergregpqqY where admin#123 is the password I use to login to Salesforce.
I have been banging my head since 2 days but not able to figure out why handshake is failing. Any suggestions?
I believe that the authorization key is incorrect. It is not your password that is expected but an OAuth access token or session id that you receive after you log into salesforce. See the different OAuth flows, if you are testing you can use the username password flow.
The following method u can use to get the session id when needed
import requests
import json
LOGIN_INSTANCE_URL = 'https://test.salesforce.com/services/oauth2/token'
LOGIN_USER_NAME = 'username_here'
CLIENT_ID = 'connected app consumer key'
CLIENT_SECRET = 'connected app consumer secret'
PASSWORD = 'password token'
def connect(authUrl, clientId, secret, username, password):
headers = {
}
postBody = {
'grant_type': 'password',
'client_id': clientId,
'client_secret':secret,
'username': username,
'password': password
}
try:
response = requests.post(authUrl, data = postBody, headers = headers)
#response.raise_for_status()
if (response.status_code == 200):
authResponse = response.json()
return authResponse['access_token']
else: #if not 200 see what the problem was
print response.text
except requests.exceptions.RequestException as e:
print e
print(connect(LOGIN_INSTANCE_URL, CLIENT_ID, CLIENT_SECRET, LOGIN_USER_NAME, PASSWORD))
This is just sample code that should work, but you need to create a connected app first. for stand alone app without user intervention JWT flow is better.

Resources