pythonflask

Use secret key to secure flask API - python


Is it possible to use a secret key to secure just an API without a website or webpage?

I made an app that uses flask and when I test it from the client app, it works. However I want to secure the get request from the client to the server by using a secret key or token if possible.

The problem is that most examples I have seen assumed you are using this for a website with login credentials. I don't have any webpages or any routes in my flask app.

Here is the server side:

from flask import Flask, stream_with_context, request, Response
from flask_restful import Api, Resource
from flask_socketio import SocketIO
import intermedia_choose_action_flask 
import subprocess
from io import StringIO 
import sys
import sqlite_companysearch
import time

app = Flask(__name__)
api = Api(app)
SECRET_KEY = "a long set of strings I got from running a command in linux terminal"

app.secret_key = SECRET_KEY

class addspamblacklistspecific(Resource):
    def get(self, emailordomain):
        count = 0
        sqlite_companysearch.comp_searchall_intermedia()
        selection_cid = sqlite_companysearch.comp_searchall_intermedia.cid_selection_results            
        for cid in selection_cid:
            
            subprocess.Popen(["python3", "/home/tech/scripts/Intermedia_automate/intermedia_choose_action.py", "--addblockspecific", "--cp", cid, "--ed", emailordomain], bufsize=10, errors='replace')
            count = count + 1 
            if count == 3:
                time.sleep(60)
                count = 0

        return "command completed succesfully"

        

api.add_resource(addspamblacklistspecific, "/addspamblacklistspecific/<string:emailordomain>")
if __name__ == "__main__":
    app.run(debug=True)

Here is the client side:

from flask import json
import requests

#where do I put in a secret key?

def email_or_domain_selection():
    email_or_domain_selection.email_select = input("""Enter an email or domain.
(NOTE: domains must have a "*" symbol infront of the name. For example *company.com)

Enter Email or Domain :""")
    eselect = email_or_domain_selection.email_select
    return email_or_domain_selection.email_select
email_or_domain_selection()

BASE = "http://127.0.0.1:5000/"

response = requests.get(BASE + "addspamblacklistspecific/"+email_or_domain_selection.email_select)
print(response.text)

I figure I should learn this before learning how to put my app in the cloud.

Thank you for your time,

Edit - I was told to read this: demystify Flask app.secret_key which I already did. That is for if you have webpages. I don't have any webpages and am just trying to secure an API only. It doesn't explain how or if I should be using session information for just calling an api from a client side. It doesn't explain how to use a secret key on the client side.


Solution

  • You could look into flask-httpauth. I used this a while back on one of my projects to add a layer of security to some API's running on flask. Keep in mind that this is only a basic authentication (base-64 encoded strings).

    from flask import Flask, jsonify, request
    from flask_restful import Resource, Api
    from flask_httpauth import HTTPBasicAuth
    
    
    # import credentials from env (suggested)
    API_UNAME = "username"
    API_PASS = "password"
    
    USER_DATA = {API_UNAME: API_PASS}
    
    
    # initialize flask/flask-restful instance
    app = Flask(__name__)
    api = Api(app)
    auth = HTTPBasicAuth()
    
    
    class API_Class(Resource):
        @auth.login_required
        def post(self):
            # do api stuff
            return jsonify("result")
    
    
    # verify API authentication
    @auth.verify_password
    def verify(username, password):
        if not (username and password):
            return False
        return USER_DATA.get(username) == password
    
    
    api.add_resource(API_Class, "/post")
    

    You might want to look into other methods like OAuth for extra security.