Search code examples
flasktokenjwt

No Access Token in Header Even After Specifying It : Flask & JWT


I have created a basic application using flask, sqlite3, sqlalchemy and JWT for user authentication. My decorator is as follows [please excuse the formatting i assure you the indentation is correct in the code]:

def token_required(f):
  @wraps(f)
  def decorated(*args, **kwargs):
    token = None
    print(request.headers)
    if 'x_access_token' in request.headers:
        token = request.headers['X-Access-Token']

    if not token:
        return jsonify({'message' : 'Token is missing.'}), 401

    try:
        data = jwt.decode(token, SECRET_KEY)
        current_user = User.query.filter_by(public_id=data['public_id']).first()
    except:
        return jsonify({'message': 'Token is invalid.'}), 401

    return f(current_user, *args, **kwargs)
return decorated

My main login route is where i ask for a username and password, and if that works i pass along a jwt token in the header to my routes that require a token:

@Main.route('/login', methods=['GET', 'POST'])
def login():
auth = request.authorization

if not auth or not auth.username or not auth.password:
    return make_response('Could not verify!', 401, {'WWW-Authenticate' : 'Basic realm="Login Required!"'})

user = User.query.filter_by(username=auth.username).first()

if not user:
    return make_response('Could not verify!', 401, {'WWW-Authenticate': 'Basic realm="Incorrect username"'})

if check_password_hash(user.password, auth.password):
    token = jwt.encode({'public_id' : user.public_id,
                        'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds=5000)},
                        SECRET_KEY)
    response = redirect(url_for('Main.views'))
    response.headers['X-Access-Token'] = token.decode('UTF-8')
    print('hi', response.headers)
    return response
    # return response_builder('Main.views', token)
else:
    return make_response('Could not verify!', 401, {'WWW-Authenticate': 'Basic realm="Incorrect password"'})

But when my route called views is opening it cant find the token in the header causing the else part of my decorator to be executed i.e. missing token.

I printed out the headers i send in my response from /login:

Content-Type: text/html; charset=utf-8
Content-Length: 219
Location: /views
X-Access-Token: [a long hashed value]

And when i print the headers in the decorator for my view that login redirects to there is no x-access-token!

Host: localhost:5000
Connection: keep-alive
Cache-Control: max-age=0
Authorization: Basic YWJoaTphYmhp
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like 
Gecko) Chrome/83.0.4103.61 Safari/537.36
Accept: 
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;
q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: Pycharm-6d7a12e6=5d65ff91-afab-45ec-8de8-a23e44c046dd; __test=1; username-localhost- 
8888="2|1:0|10:1590510962|23:username-localhost- 
8888|44:MTA2YjkyMWJiMmU2NDU1MGFmM2Q5MjZhZGE5YjEwODA=|
f3ea838f5405f6c102ddbaf45dfef9bd000d2d183eaba9310d698d1005a6c21b"; 
session=eyJkYl9uYW1lIjoibXlfaGlzdCJ9.Xt-9aA.vDjCIXn731CioU72zCiJFim1shg

This is my view that requires a token:

 # views page for navigation
    @Main.route('/views')
    @token_required
    def views(current_user):
        print(current_user)
        return render_template('Main/Views.html')

Another method i tried instead of redirect is make_response and that dint work either, it seems to just skip the decorator and render /views on the page. Not the html of /views but literally /views


Solution

  • Headers, except simple ones, cannot be set in between.

    no-cors — Prevents the method from being anything other than HEAD, GET or POST, and the headers from being anything other than simple headers. If any ServiceWorkers intercept these requests, they may not add or override any headers except for those that are simple headers. In addition, JavaScript may not access any properties of the resulting Response. This ensures that ServiceWorkers do not affect the semantics of the Web and prevents security and privacy issues arising from leaking data across domains.