Hello.
I have a frontend nextjs application with microsoft entra login, I get the access and refresh token and store them.
I have then a python backend that does api calls of microsoft to get user inboxes and emails
I am getting right now the error
{"error":"invalid_grant","error_description":"AADSTS50013: Assertion failed signature validation. [Reason - Key was found, but use of the key to verify the signature failed., Thumbprint of key used by client
What is the fix that I need to do on the OnBehalfOfCredential?
I have this scopes
User.Read Mail.Read email Mail.ReadBasic Mail.ReadWrite
My code
"""
Microsoft API Service
"""
import os.path
import logging
import configparser
import datetime
from flask import Flask, g, request, jsonify
from flask_cors import CORS
from src.routes.emails.messages import email_messages
from src.routes.labels.labels import labels_route
from src.config.graph import Graph
from src.config.tokenCredentials import RefreshableTokenCredential
# from src.routes.aifeatures import aifeatureUtils
from src.shared import db
app = Flask(__name__)
# app.register_blueprint(aifeatureUtils, url_prefix="/ai")
app.config['CORS_HEADERS'] = 'Content-Type'
cors = CORS(app, resources={r"/*": {"origins": "*"}})
# logger = logging.getLogger(__name__)
# logging.getLogger().setLevel(logging.INFO)
# logging.getLogger().addHandler(handler)
def authenticate_api_key(api_key):
return api_key in db.get_all_api_keys()
@app.before_request
def before_request_api_check():
g.email = request.headers.get("email") or request.args.get("userId")
api_key = request.headers.get('API-Key')
if not api_key or not authenticate_api_key(api_key):
return jsonify({'error': 'Unauthorized'}), 401
@app.before_request
def before_request():
config = configparser.ConfigParser()
config.read(['config.cfg', 'config.dev.cfg'])
azure_settings = config['azure']
try:
print("Getting account data")
g.user = db.get_account(g.email)
g.access_token = g.user['access_token'] # Assuming the user's access token is stored in the account data
g.refresh_token = g.user['refresh_token']
g.expires_at = g.user['expires_at']
g.email = g.user['email']
except Exception as e:
app.logger.error("%s Error getting account data: %s", g.email, str(e))
return {
"success": False,
"error": f"Error getting account data: {str(e)}"
}, 400
graph: Graph = Graph(azure_settings)
g.microsoft_service = graph
#Registering the blueprints
app.register_blueprint(email_messages)
app.register_blueprint(labels_route)
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 5051)))
from flask import Blueprint, g, jsonify
labels_route = Blueprint('labels_route', __name__, template_folder='templates')
@labels_route.route("/get-labels", methods=["GET"])
async def get_labels_sync():
try:
print("Getting labels")
response = await g.microsoft_service.user_client.me.mail_folders.get()
return {
"success": True,
"labels": response
}
except Exception as e:
print(f"Error getting labels: {str(e)}")
return {
"success": False,
"error": f"Error getting labels: {str(e)}"
}, 400
from configparser import SectionProxy
from azure.identity import DeviceCodeCredential, OnBehalfOfCredential
from msgraph import GraphServiceClient
from azure.core.credentials import AccessToken
from flask import g
class Graph:
settings: SectionProxy
device_code_credential: DeviceCodeCredential
access_token_credential: AccessToken
user_client: GraphServiceClient
def __init__(self, config):
self.settings = config
client_id = self.settings['clientId']
tenant_id = self.settings['tenantId']
graph_scopes = self.settings['graphUserScopes'].split(' ')
self.device_code_credential = DeviceCodeCredential(client_id, tenant_id = tenant_id)
credential = OnBehalfOfCredential(
tenant_id=tenant_id,
client_id=client_id,
client_secret=self.settings['clientSecret'],
user_assertion=g.access_token
)
self.user_client = GraphServiceClient(credentials=credential, scopes=graph_scopes)