“alg” field mismatch issue with Auth0 and Python backend / React JS Frontend

First off, I feel awful for posting this since I’ve seen similar people having this same issue so I apologies in advance if my oversight is simple or has been answered 100 times. I’ve just been spending like 10 hours or more debugging and trying to figure this out and have had no luck. Been trying to use every resource I can find. I’ve been working on a project learning coding working with Python, React JS and PostgreSQL database stack - so I’m by no means advance but been learning these past 6 months.
(removing links since new users are limited to 3 links)

I’m having a terrible time trying to pass the JWT token from my frontend (React JS) to my backend (Python / Flask) so then I can pass some user information over to my database (PostgreSQL).

  • My domain of my Auth0 Application is: dev-s1ihogvw5buvwqxv.us.auth0 . com

  • Allowing Cross-Origin Authentication

  • Set Allowed callbacks to - localhost:3000/, dev-s1ihogvw5buvwqxv.us.webtask.run/auth0-authentication-api-debugger

    • I set the dev-s1ihogvw5buvwqxv.us.webtask.run/auth0-authentication-api-debugger for debugging purposes which worked. However doesn’t work on my localized project.
  • My API Identifier s1WgRsk3Z8eZhNrwPnyGiNT3J3p0i0HV-api has been used in my .env’s and also is using RS256 signing algorithm

The issue / Errors:
{alg: ‘dir’, enc: ‘A256GCM’, iss: ‘dev-s1ihogvw5buvwqxv.us.auth0 . com/’}
Browser Console Logs: (using placeholder info for user details in this post) The username and emails are correct with what were entered

Use Effect Tokens: User profile:

  1. {email: ‘someemail@gmail.com’, username: ‘MyUserName’}

App.js:91 Checking tokens remaining

App.js:92 User:

  1. {given_name: ‘Name’, family_name: ‘Name’, nickname: ‘MyUserName’, name: ‘Name’, picture: ‘lh3.googleusercontent/a/ACg8ocJHVTG…’, …}

App.js:61 SendUserDataToBackend: Access Token: eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtczFpaG9ndnc1YnV2d3F4di51cy5hdXRoMC5jb20vIn0…blgXp2Ae9pOdQq1O.m70nAacRJdilYM-e8JDWHSPzIPZsyU5qmtrmlCk8XqCmsE53zLZHmJdsOKOwirEjHRGSgSWWulevUut2alqcqtAPV9t2RwFnfSeKId51B4D2zvWErj75hTCHMOpc0L-2B5Uwn73MXWfgmCtRTJdUa0HpukY2xW0DriWAe3577fMMTjLscaSTZGdCFumrgdU4g_RL_2YxsrZYaphre9wNQCifb5M5dSsWJFQh6qaoeTBKWVD3tu1o1RVHhlUwHBm9fkEecDTjC6Rxc5g3umr2-9ASDx4AIoIeGSQnSTreBUpKfT3QhzogItGw6u8-ZimHzRHXRmir3dvG7kNsKaJOE7pT_tlEmRw.1383Chfc-hwqpxdsy21SwA

App.js:65 Decoded Header:

  1. {alg: ‘dir’, enc: ‘A256GCM’, iss: ‘dev-s1ihogvw5buvwqxv.us.auth0.com/’}

App.js:94 Access Token: … same as above …

main.js?attr=T8lVLyX…mhVYUTnLQjd38o:3494 GET 127.0.0.1:5000/get_tokens_remaining 422 (UNPROCESSABLE ENTITY)

main.js?attr=T8lVLyX…mhVYUTnLQjd38o:3494 POST 127.0.0.1:5000/auth/register 422 (UNPROCESSABLE ENTITY)

App.js:77 User data saved:

  1. {error: “Invalid payload string: ‘utf-8’ codec can’t decode byte 0xa7 in position 3: invalid start byte”, message: ‘Invalid token’}

  2. error: “Invalid payload string: ‘utf-8’ codec can’t decode byte 0xa7 in position 3: invalid start byte”

  3. message: “Invalid token”

  4. [[Prototype]]: Object

Python Terminal Error Print Outs:

Press CTRL+C to quit
127.0.0.1 - - [07/Nov/2023 18:18:19] “OPTIONS /auth/register HTTP/1.1” 200 -
127.0.0.1 - - [07/Nov/2023 18:18:19] “OPTIONS /get_tokens_remaining HTTP/1.1” 200 -
Invalid token callback error: Invalid payload string: ‘utf-8’ codec can’t decode byte 0xec in position 0: invalid continuation byte
Invalid token callback error: Invalid payload string: ‘utf-8’ codec can’t decode byte 0xec in position 0: invalid continuation byte
Error type: <class ‘str’>
Error type: <class ‘str’>
Headers: Host: 127.0.0.1:5000
Connection: keep-alive
Sec-Ch-Ua: “Google Chrome”;v=“119”, “Chromium”;v=“119”, “Not?A_Brand”;v=“24”
Sec-Ch-Ua-Mobile: ?0
Authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtczFpaG9ndnc1YnV2d3F4di51cy5hdXRoMC5jb20vIn0…7CG4JMoA95Qi4Qbv.UtNQ9g4kcMDoBLe9n2AE_uEYoTLqY_7Dxo3CN6q-_D24j2rKAVTcBastSWkR7F3V2nooHze5-7RHQBI31QMjrpaaLOYx2-I7STr36Gq-tOWmnHNTfrqbIpCfAVKU6NhN-x44nSqkRzmp9Rmr6LYRm1Fp5NoXpyY3BfbXoOwCXRMQajobd5SurK6vHrm5VcjWY8lpcgJBHIIt15InmlHuPcrxVuunHT6r5nxEaqCp7SHqNFbmZAuVSv4UWsimQW8AxHM-vPLeHh-gLPPO6GNLiKKbrcuHNDUTybxVvUm1oakYktszhXpnTa-WTEltJcSCKy8Q4Jzr7C7FKk2o5_F6KLQLbFf-s-U.lAwAWnxSYhO7ff1mgcLzTA
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
Sec-Ch-Ua-Platform: “Windows”
Accept: /
Origin: http://localhost:3000
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

Headers: Host: 127.0.0.1:5000
Connection: keep-alive
Content-Length: 56
Sec-Ch-Ua: “Google Chrome”;v=“119”, “Chromium”;v=“119”, “Not?A_Brand”;v=“24”
Content-Type: application/json
Sec-Ch-Ua-Mobile: ?0
Authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtczFpaG9ndnc1YnV2d3F4di51cy5hdXRoMC5jb20vIn0…7CG4JMoA95Qi4Qbv.UtNQ9g4kcMDoBLe9n2AE_uEYoTLqY_7Dxo3CN6q-_D24j2rKAVTcBastSWkR7F3V2nooHze5-7RHQBI31QMjrpaaLOYx2-I7STr36Gq-tOWmnHNTfrqbIpCfAVKU6NhN-x44nSqkRzmp9Rmr6LYRm1Fp5NoXpyY3BfbXoOwCXRMQajobd5SurK6vHrm5VcjWY8lpcgJBHIIt15InmlHuPcrxVuunHT6r5nxEaqCp7SHqNFbmZAuVSv4UWsimQW8AxHM-vPLeHh-gLPPO6GNLiKKbrcuHNDUTybxVvUm1oakYktszhXpnTa-WTEltJcSCKy8Q4Jzr7C7FKk2o5_F6KLQLbFf-s-U.lAwAWnxSYhO7ff1mgcLzTA
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
Sec-Ch-Ua-Platform: “Windows”
Accept: /
Origin: localhost : 3000
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: localhost : 3000
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

127.0.0.1 - - [07/Nov/2023 18:18:19] “GET /get_tokens_remaining HTTP/1.1” 422 -

127.0.0.1 - - [07/Nov/2023 18:18:19] “POST /auth/register HTTP/1.1” 422 -

My basic structure is:
Python Backend: 127.0.0.1:5000

  • Python/main.py - initializing the Flask app, pulling in the .env variables and setting the JWT information, handling main page function

  • Python/.env - calling in CLIENT_ORIGIN_URL, AUTH0_AUDIENCE, AUTH0_DOMAIN, AUTH0_CLI and AUTH0_CLIENT_SECRET

  • extensions.py - importing flask_jwt_extended JWTManager and setting jwt = JWTManager()

  • Python\src\accounts\auth.py - handling jwt token errors, register_user function and routing.

Frontend structure: - localhost:3000/

  • App.js - main app initialization and functions / homepage

  • index.js - ReactDOM.render and Auth0Provider wrapper

  • .env - calling in REACT_APP_AUTH0_AUDIENCE, REACT_APP_AUTH0_DOMAIN and REACT_APP_AUTH0_CLIENT_ID

Here’s the code snippets and how I’m trying to pass the information through from the frontend to the backend.

App.js
sharing more than may be needed to see if there may be something else that’s hanging the program up

import React, { useState, useEffect } from 'react';
import './App.css';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import { Auth0Provider, useAuth0 } from '@auth0/auth0-react';

function App() {
    const {
        isAuthenticated,
        loginWithRedirect,
        logout,
        isLoading,
        getAccessTokenSilently,
        user
    } = useAuth0();

   //...various const instances in my web app... 

    //Sender Information to the backend
    const sendUserDataToBackend = async (userData) => {
        try {
            const accessToken = await getAccessTokenSilently({
                audience: 'https://s1WgRsk3Z8eZhNrwPnyGiNT3J3p0i0HV-api',
                scope: 'openid email profile'
            });
            console.log("SendUserDataToBackend: Access Token:", accessToken);
    
            // Before sending, let's log the decoded header of the token to check its type (JWT vs JWE)
            const decodedHeader = JSON.parse(atob(accessToken.split('.')[0]));
            console.log("Decoded Header:", decodedHeader);
    
            const response = await fetch('http://127.0.0.1:5000/auth/register', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${accessToken}`, // Send the Auth0 access token in the header
                },
                body: JSON.stringify(userData),
            });
    
            const responseData = await response.json();
            console.log('User data saved:', responseData);
        } catch (error) {
            console.error('Error sending user data to backend:', error);
        }
    };
    //Check for Tokens or Credits remaining
    useEffect(() => {
        if (isAuthenticated) {
            const userProfile={
                email: user.email,
                username: user.username || user.nickname,
            };
            sendUserDataToBackend(userProfile);
            console.log("Use Effect Tokens: User profile:", userProfile);
            console.log("Checking tokens remaining");
            console.log("User:", user);
            getAccessTokenSilently().then((accessToken) => {
                console.log("Access Token:", accessToken);
                // Use accessToken for your authenticated requests
                fetch(`http://127.0.0.1:5000/get_tokens_remaining`, {
                    headers: {
                        Authorization: `Bearer ${accessToken}`,
                    },
                    credentials: 'include',
                })
                .then(response => response.json())
                .then(data => {
                    setTokensRemaining(data.tokens_remaining);
                })
                .catch(error => {
                    console.error("Error fetching tokens remaining:", error);
                });
            });
        }
    }, [isAuthenticated, getAccessTokenSilently, user]);
    const handleGenerateBeat = () => {
        
        if (!isAuthenticated){
            alert("You must be logged in to generate a beat.");
            return;
        }
        setAudioWaveform(null);
        setLoading(true);
        fetch('http://127.0.0.1:5000/', {
            credentials: 'include',
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ title: beatTitle }),
        })
        .then(response => response.json())
        .then(data => {
            console.log("Recieved audio URL: ", data.audio_url)
            setAudioWaveform(data.audio_url);
            setProducerInfo(data.producer_info || []);
            setLoading(false);
        })
        .catch(error => {
            console.error("Error fetching data:", error);
            setLoading(false);
        });
    }
    const handleLogout = () => logout({ returnTo: window.location.origin });


index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Auth0Provider } from "@auth0/auth0-react";

const domain = process.env.REACT_APP_AUTH0_DOMAIN;
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
const audience = process.env.REACT_APP_AUTH0_AUDIENCE;

ReactDOM.render(

  <React.StrictMode>  
<Auth0Provider
  domain={domain}
  clientId={clientId}
  redirectUri={window.location.origin}
  audience={audience}
  scope="openid profile email"
>
  <App />
</Auth0Provider>

  </React.StrictMode>,
 
  document.getElementById('root')
);

auth.py:

** Calling and initializing imports **

auth_bp = Blueprint('auth_bp', __name__)

Session = sessionmaker(bind=db_manager.engine)
session = Session()

@jwt.unauthorized_loader
def unauthorized_callback(callback):
    return jsonify({'message': 'Missing or invalid token'}), 401

@jwt.expired_token_loader
def expired_token_callback(callback):
    return jsonify({'message': 'Expired token'}), 401

@jwt.invalid_token_loader
def invalid_token_callback(error):  # Pass the error argument to get more details
    headers = request.headers
    print(f"Invalid token callback error: {error}")  # Log the error for debugging
    print(f"Error type: {type(error)}")
    print(f"Headers: {headers}")
    return jsonify({'message': 'Invalid token', 'error': str(error)}), 422

@auth_bp.route('/register', methods=['POST'])
@jwt_required()
def register_user():
    print("JWT Token is present, entered register route!")
    print("Entered register route!")
    print(f"Received data: {request.json}")
    print(f"Email: {request.json.get('email')}")
    print(f"Username: {request.json.get('username')}") 
    # Since we are using Auth0, we assume that we have already verified
    # the user's email and they have been authenticated
    current_user_info = get_jwt_identity()
    user_email = current_user_info['email']
    username = current_user_info.get('username')  # How you access this depends on how the JWT token is structured
    print(f"User info: {current_user_info}")
    print(f"Email: {user_email}")
    print(f"Username: {username}")

    # Check if the user already exists in your DB
    existing_user = session.query(User).filter_by(email=user_email).first()
    if existing_user:
        return jsonify({'message': 'User already exists'}), 409
    
    # Create a new user without the password since it's managed by Auth0
    current_time = datetime.utcnow()
    new_user = User(
        email=user_email,
        username=username,
        is_admin=False,
        created_at=current_time,
        updated_at=current_time
    )
    try:
        session.add(new_user)
        session.commit()
    except Exception as e:
        print(f"Failed to add new user to the database! Error: {e}")
        session.rollback()
        return jsonify({'message': 'Failed to register user'}), 500
    # Insert the user's subscription details
    # Assuming 'Free' tier exists and you have a method to get its details
    free_subscription = session.query(Subscription).filter_by(name='Free').first()
    if free_subscription:
        user_subscription = UserSubscription(
            user_id=new_user.id,
            subscription_id=free_subscription.id,
            start_date=current_time,
            tokens_remaining=free_subscription.tokens_per_month
        )
        session.add(user_subscription)
        session.commit()

    return jsonify({'message': 'User registered successfully'}), 201

main.py:

** Calling and initializing imports **

load_dotenv()

app = Flask(__name__)

login_manager.init_app(app)
login_manager.login_view = 'auth_bp.login'
CORS(app, origins=["http: localhost:3000", "http: 127.0.0.1:5000"], supports_credentials=True)
CLIENT_ORIGIN_URL = os.getenv('CLIENT_ORIGIN_URL')
AUTH0_AUDIENCE = os.getenv('AUTH0_AUDIENCE')
AUTH0_DOMAIN = os.getenv('AUTH0_DOMAIN')
AUTH0_CLIENT_ID = os.getenv('AUTH0_CLIENT_ID')
AUTH0_CLIENT_SECRET = os.getenv('AUTH0_CLIENT_SECRET')
ALGORITHMS = ["RS256"]

app.config['JWT_HEADER_NAME'] = 'Authorization'
app.config['JWT_HEADER_TYPE'] = 'Bearer'
app.config['JWT_TOKEN_LOCATION'] = ['headers']
app.config["JWT_PUBLIC_KEY"] = json.loads(urlopen(f"https://{AUTH0_DOMAIN}/.well-known/jwks.json").read())
app.config['JWT_ALGORITHM'] = 'RS256'
app.config["JWT_DECODE_AUDIENCE"] = AUTH0_AUDIENCE
jwt.init_app(app)

app.register_blueprint(auth_bp, url_prefix='/auth')


@app.route('/GeneratedBeats/<filename>', methods=['GET'])
def serve_audio(filename):
    return send_from_directory('./GeneratedBeats', filename)
        
@app.route('/get_tokens_remaining', methods=['GET'])
@jwt_required()  # Require a valid JWT token to access this endpoint
def get_tokens():
    print("Get Tokens main.py - ",request.cookies)
    current_user = get_jwt_identity()
    user_id = current_user['user_id']
    if user_id is not None:
        tokens_remaining = get_tokens_remaining(user_id)
        return jsonify({'tokens_remaining': tokens_remaining})
    else:
        return jsonify({'error': 'User not logged in'}), 401

...additional functions for rest of web app...

Sorry for the long and detailed post, just figured to share whatever that might help in order to help solve what I could possibly be doing wrong.

Hi @TrapDeer,

Welcome to the Auth0 Community!

I’m guessing (I’m not able to decode the header for the token you provided.) the access token you are being returned is an Opaque Token.

In order to retrieve a token that your API can decode, you must pass a valid audience parameter with the request to authorize/login. I see you have an audience, but I suspect it isn’t valid and you aren’t returned a JWT (non-opaque token).

Try creating a new API in the Auth0 dashboard. We suggest using a URI for the API Identifier/audience. You could try the following for example: https://test-api

Now send audience: 'https://test-api' with your request to login.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.