Authenticating to Reddit with Python Flask and PRAW
Enable users authenticate to Reddit securely via your Python Application with Oauth
In this article I’ll explain how to let users sign in to their Reddit account from your Python based application using a concept of OAuth. You might be building an API or a web-server that uses Reddit data and you want to enhance the experience by allowing Reddit users to authenticate and provide you their permission. There are numerous ways to allow the user to sign in, the most trusting and secure way is to not touch their credentials at all.
tl;dr — you can find the complete code here in this gist.
The minimum requirements for this project are:
- Basic understanding of Python
- PRAW — Python Reddit API Wrapper
- Flask or similar web framework
- Reddit Developer Account for testing
How does OAuth work?
In basic terms, the user visits your site where they are prompted in some way to sign-in. The sign-in action triggers their browser to redirect to Reddit.com where your web server has asked for permission to their account.
Reddit confirms this request with the user, if the user approves, Reddit returns the user back your web server along with an authorization code. Your web server then needs to exchange this code for a token. The code is exchange is used as an added layer of security. The beauty of OAuth is you never have to see or handle the users credentials, this creates an added layer of trust and privacy.
We can use OAuth to validate the suer is who they say they are by using another service providers identity management instead of our own. We can also be granted extra permissions, in our case, permissions to access Reddit on their behalf.
The authorization code is a temporary code that the client will exchange for an access token. The code itself is obtained from the authorization server where the user gets a chance to see what the information the client is requesting, and approve or deny the request. Read More
Once you have obtained the token you can now act on the user’s behalf and perform any action that you were approved permission for as if you were the user, such as:
- Delete Comments/Posts
- Update profile
Setting up a Developer Account
The first step before we can begin is to register an application with Reddit. This is easily done with any Reddit account. I recommend for testing you use a throw-away account just in case you perform an action that gets your account banned or muted.
Go to Reddit.com and login to your chosen account, from the Top-right Menu select User Settings.
From your user settings page, select Safety & Privacy from the top tab menu
Scroll to the bottom and you will see a link to another page to manage third-party authorizations. If you have ever let an app act on your behalf on Reddit this is where you would find the options to revoke that permission.
This is also the same page where we register our own Reddit apps.
Once there you should hopefully see a button to create a new application. If your account is brand new it should look like below, otherwise the option will be somewhere on the page.
Now we need to fill out some details:
- Type will be Web App, for this demonstration
- Give your app a name, I have chosen my-app
- Provide a redirect URI: http://localhost:8080/callback
The redirect URI will be used by Reddit to return your user back to your web-server. If you are hosting this on a domain somewhere like http://example.com, you would use your domain name instead, followed by the endpoint you would like to use.
For this example we will run it locally specifying
http://locahost:8080 and redirect to an endpoint called
When ready, press create. You will now see your applications credentials, just under your applications name is your
Client ID and the longer string of random characters is your
Client Secret . We will need both of these later; remember to keep the secure.
Setting up Flask and PRAW
Using your IDE/Editor of choice create a new work space and a single python file called
Will will import Flask and PRAW to start with and then set up our PRAW client to connect our web-server to Reddit.
We have imported Flask and PRAW along with UUID. We will use UUID later to generate a random ID that we will use to verify the request from Reddit.
Your app.secret_key is used by Flask to secure session data like cookies. You can learn more about session data and flask here.
Note: It’s important that your
port are matching in each location, if you have connection issues during this project please ensure you use the same values everywhere. Ideally we would setup environment variables or global variables but for brevity I have hard-coded them.
Your first route
We now want to create our index route, this is the first route users will hit when they visit our web-server. Just below your previous code add the following:
For brevity I have written the HTML inline, but you might choose to serve a HTML template instead. Let’s look at what this route does.
- We check if there is a session key called
“authenticated”, if there is we return the session data we have on the user in some HTML. This assumes the user has already authenticated to Reddit and we have a token to use.
- Otherwise, we return HTML that will direct the user to the route to authorize our application. We send them a link to another endpoint we’ll create next called
Prepare for Authorize
Below your previous route, create a new route pointing at
/authorize. Here we will setup the scopes/permissions we want from the user and format a URL to redirect the user to Reddit.
We specify the scopes we want from the user, this will grant us only permission to those specific scopes. You can learn more about Reddit’s scopes here.
Next, we generate a random UUID and store it in a session called
“state_code”. When we store something like this in Flask’s session object, Flask saves a cookie to the user’s browser which is encrypted by the flask
app.secret_key. When the user leaves our site and returns, Session checks for any cookies it knows about and can read them again. We will use this UUID later to confirm that the request we sent matches the response coming back.
Finally, we return the user a redirect to the Reddit URL along with our scopes and UUID.
This route will handle the process after the user has approved the request. Reddit will send the user to this endpoint with an authorization code and our UUID.
Below your previous route, create the following:
From the top, we pull out the information from the request:
- State — this is our UUID which we will check is the same
- Code — this is an authorization code from Reddit
- Error — any errors Reddit has encountered with our request
We then handle any errors if they are present. The simplest option is to abort the process and return the error.
We then check our copy of the state code with what Reddit has returned. It should be the same one we sent. If we sent Reddit
123ABC, Reddit should send back
123ABC. If the state code is not present or does not match this can indicate a fake request from somewhere (or you have bugs in your code).
If the state code is okay we then take the authorization code and ask Reddit to exchange it for a token. The token is what gives us the actual permission to operate on the user’s behalf.
We then update our session object
True, so when the user visits the index route again it will change what HTML they receive.
Finally, we redirect back to the main/index route.
The Process in Action
The user visits our site, they haven’t authenticated so they are presented the with the following:
The user presses Authenticate and they are redirected to Reddit. Reddit confirms that the request and the permissions are what they expect. If the user approves the request they are then redirect back to our server.
Our server interprets the redirected request, we ensure the it’s legitimate and we then read the users name using PRAW and the provided token.
You should now create a route to clear the session. The below example clears the session but does not relinquish permissions for the user.
Now that you have the user’s permission, you can develop an intuitive application, the skies the limit.
- Build your own Reddit interface/app
- Build a utility to delete comments
- A application to schedule posts
- An auto reply bot
Other things to improve on:
- Store the token in session so when the user returns they don’t need to re-approve permissions (we already have permission, we just lose the token).
- Let the user revoke permissions from our end.
- Use HTTP requests instead of PRAW — Future project
Please feel free to reach out with questions or things that can be improved. If I’ve failed to elaborate on something I’m more than happy to fill in the gaps.