request.headers["X-Replit-User-Profile-Image"] not working

I am trying to get users profile pictures for an app with Replit Auth in Python and Flask but for some reason request.headers["X-Replit-User-Profile-Image"] as suggested in the #100-days-of-code and https://docs.replit.com/hosting/repl-auth-sidebar is not working?

Repl I am using to test: https://replit.com/@robsd/Replit-Auth-Image-Test-Flask

Am I missing anything obvious or does this feature no longer work?

Hello @robsd

The X-Replit-User-Profile-Image header that you mentioned is used to retrieve the user’s profile image when using Replit’s Authentication. This feature should still be working, but there may be something in your implementation that is causing it to not work.

There are a few things to check:

  • Make sure that you have enabled Replit Authentication for your app by going to the settings page of your repl and enabling it.
  • Make sure that you are sending the request to the correct endpoint. The endpoint for retrieving the user’s profile image is https://replit.com/data/users/<username>/avatar, where <username> is the user’s Replit username.
  • Make sure that you are including the correct headers in your request. In addition to the X-Replit-User-Profile-Image header, you will also need to include the Authorization header with the value of Bearer <access_token>, where <access_token> is the user’s access token.

Here is an example of how you can retrieve the user’s profile image using the requests library in Python:

import requests

headers = {
    "X-Replit-User-Profile-Image": "true",
    "Authorization": "Bearer <access_token>"
}

response = requests.get("https://replit.com/data/users/<username>/avatar", headers=headers)

if response.status_code == 200:
    profile_image = response.content
else:
    print("Error:", response.status_code)

If you are still facing the issue, you may want to check your access token if it is still valid by using the https://replit.com/data/users/me endpoint and then check the response.status_code

Also, make sure that you are running the code on a server and not on the client-side as the access token will be exposed to the client, you can use a library like Flask-JWT-Extended to secure your endpoint.

Yes, it’s important to make sure that the access token is not exposed to the client and to secure your endpoint. You can use a library like Flask-JWT-Extended to handle the authentication and authorization of your API endpoints. It provides an easy-to-use API for handling JSON Web Tokens (JWT) in your Flask application.

Here’s an example of how you can use Flask-JWT-Extended to secure your endpoint for retrieving the user’s profile image:

  1. Install the library with pip install Flask-JWT-Extended
  2. Add the following code to your Flask application:
from flask_jwt_extended import JWTManager, jwt_required

app = Flask(__name__)
app.config["JWT_SECRET_KEY"] = "your_secret_key"
jwt = JWTManager(app)

@app.route("/profile_image", methods=["GET"])
@jwt_required
def profile_image():
    headers = {
        "X-Replit-User-Profile-Image": "true"
    }
    response = requests.get("https://replit.com/data/users/<username>/avatar", headers=headers)
    if response.status_code == 200:
        return response.content, 200
    else:
        return "Error: {}".format(response.status_code), response.status_code

This way only user with valid JWT token will be able to access the endpoint.

Also, make sure that you are using a secure way to store and transmit the access token, such as using HTTPS.

It’s important to note that the above example is a simple implementation of securing an endpoint using JWT, in a real-world scenario, you should also handle the token generation and validation, as well as the user authentication process, which typically involves checking the user’s credentials against a database and issuing a token if the credentials are valid.

Here’s an example of how you can handle the token generation and validation process:

  1. Create a route for generating a token:
from flask_jwt_extended import create_access_token

@app.route("/login", methods=["POST"])
def login():
    # Authenticate the user
    if not authenticate(request.form["username"], request.form["password"]):
        return "Invalid credentials", 401

    # Generate an access token
    access_token = create_access_token(identity=request.form["username"])
    return {"access_token": access_token}, 200
  1. In the above example, the authenticate() function should check the user’s credentials against a database and return True if the credentials are valid, and False otherwise.
  2. You can also add a route for refreshing the token:
from flask_jwt_extended import create_refresh_token

@app.route("/refresh", methods=["POST"])
@jwt_refresh_token_required
def refresh():
    current_user = get_jwt_identity()
    new_token = create_access_token(identity=current_user)
    return {"access_token": new_token}, 200
  1. You can also add a route for logging out
from flask_jwt_extended import jwt_required, get_raw_jwt

@app.route("/logout", methods=["DELETE"])
@jwt_required
def logout():
    jti = get_raw_jwt()["jti"]
    blacklist.add(jti)
    return "Successfully logged out", 200

By using this method, you can ensure that only authorized users can access the protected endpoints, and that the token is valid and has not been tampered with.

It’s important to also store the refresh token securely and only issue it over a secure connection such as HTTPS, and to store the JWT in a HttpOnly and Secure cookies.

Just to summarize, in order to securely retrieve the user’s profile image using Replit Auth in a Flask application, you need to follow these steps:

  1. Enable Replit Authentication for your app by going to the settings page of your repl and enabling it.
  2. Use the requests library to send a GET request to the endpoint https://replit.com/data/users/<username>/avatar, where <username> is the user’s Replit username.
  3. Include the X-Replit-User-Profile-Image header with the value of true and the Authorization header with the value of Bearer <access_token>, where <access_token> is the user’s access token.
  4. Use the Flask-JWT-Extended library to handle the authentication and authorization of your API endpoints.
  5. Handle the token generation and validation process by creating routes for generating and refreshing tokens and logging out.
  6. Store the refresh token securely and only issue it over a secure connection such as HTTPS, and store the JWT in a HttpOnly and Secure cookies.

It is also important to validate that the request is coming from a valid user, you can use the https://replit.com/data/users/me endpoint to validate the user and the access token

I hope this helps! Let me know if you have any other questions. :slight_smile:

1 Like

Hey @robsd!
You can’t just return the image src. You need to use an <img> tag using HTML.
Here is what your code would look like using an <img> tag:

from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def index():
	if request.headers["X-Replit-User-Id"]:

		image = request.headers["X-Replit-User-Profile-Image"]
		
		if image:
			return f"<img src='{image}' alt='Profile Picture' height='250' width='250'>"
		else:
			return "Couldn't Get Image"

	else:
		return "Not Logged In"

app.run('0.0.0.0')

As a result, @robsd I examined your code and discovered that request.headers["X-Replit-User-Profile-Image"] returns None because you have not implemented replit auth in your code. To accomplish this, create an HTML template that employs replit auth.

2 Likes

Eureka, I’ve got it! So you will have to change your repl for this repl (just fork it). This repl gives you the username and id of the user. And then change all the code in the index.html inside the templates folder :

<!doctype html>
<html>
<head>
	<title>Repl Auth</title>
<script src="https://replit.com/public/js/repl-auth-v2.js"></script>
</head>
<body>
	{% if user_id %}
	<h1>Hello, {{ user_name }}!</h1>
	<p>Your user id is {{ user_id }}.</p>
	<img src="{{ user_image }}" alt="User's Auth Location">
	{% else %}
	Hello! Please log in.
	<div>
<button onclick="LoginWithReplit()"> Login </button>
</div>
{% endif %}

</body>
</html>

This code will give you the username, id, and image. And your python file should have this code, so change all the code that you see already on the main.py for this on :

from flask import Flask, render_template, request

app = Flask('app')

@app.route('/')
def hello_world():
    print(request.headers)
    return render_template(
        'index.html',
        user_id=request.headers['X-Replit-User-Id'],
        user_name=request.headers['X-Replit-User-Name'],
        user_image=request.headers['X-Replit-User-Profile-Image']
    )

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080)

Thank you for looking, I was just returning the src of the image in plaintext as a test but because the “X-Replit-User-Profile-Image” header doesn’t return a value, it still doesn’t work out of the box.

1 Like

I turned on Replit Auth and using the default configuration, not custom page, but even custom page doesn’t seem to allow the “X-Replit-User-Profile-Image” to populate with a value.

I’ve tried forking that repl and the “X-Replit-User-Profile-Image” header still doesn’t return a value. The “X-Replit-User-Id” and “X-Replit-User-Name” both do though. Either it’s something to do with my Replit account or I will need to use the API to get the avatar image instead of relying on Replit Auth out of the box.

1 Like

Works perfectly for me, I’ll do a repl later for this!

That’s really strange, go this page and tell me if you see you’re picture once you pass through the auth : https://sd.hugo.repl.co/

are you returning the image in a <img> html tag?

I just get a broken image and there’s no URL passed in source on the frontend…

If that’s working for you then I genuinely think something’s up with my Replit account lol. I’ve checked all the settings tho and there’s nothing like privacy or anything to do with that.

Strange, it worked for other people.

Yeah. I even tried it with my old Uni account (default profile pic), still nothing…

image

Yep, pls see my updated Repl. I even try to print the image URL to the console along with the ID and username but only the image one is blank weirdly.

https://replit.com/@robsd/Replit-Auth-Image-Test-Flask#templates/index.html

Hello there, @robsd. I went over your code again and determined that the error was caused by an if statement that did nothing. So I replicated your code and fixed the error; please let me know if you can see your avatar!

robsd

if request.headers["X-Replit-User-Id"]:, why did you leave this if statement on a cliffhanger? if request.headers["X-Replit-User-Id"] == None: or something.

I’m pretty sure all "X-Replit-User..." headers are set to “” or something initially :stuck_out_tongue:

1 Like

I fixed his error.

working.

oh ok, sorry to bother

1 Like