Hello,
I’m developing a Slack Bot and it uses an Jira OAuth App to login in to the user jira account.
Here is a snippet of my code (python):
@app.route('/login', methods=['POST'])
def login():
data = request.form
user_id = data.get('user_id')
channel_id = data.get('channel_id')
jira_authorize_url = "https://auth.atlassian.com/authorize"
params = {
'audience': 'api.atlassian.com',
'client_id': os.environ['JIRA_CLIENT_ID'],
'scope': 'read:jira-user read:jira-work manage:jira-project manage:jira-configuration read:issue:jira write:issue:jira',
'redirect_uri': os.environ['JIRA_REDIRECT_URI'],
'state': user_id,
'response_type': 'code',
'prompt': 'consent'
}
login_url = f"{jira_authorize_url}?{requests.compat.urlencode(params)}"
client.chat_postMessage(channel=channel_id, text=f"Please log in to Jira: {login_url}")
@app.route('/listprojects', methods=['POST'])
def list_projects():
data = request.form
user_id = data.get('user_id')
# Fetch the access token from the database
c.execute('SELECT access_token FROM tokens WHERE user_id = ?', (user_id,))
result = c.fetchone()
if result is None:
return Response("You need to log in first. Use /login.", status=200)
access_token = result[0]
# Fetch cloud ID
try:
cloud_id = get_cloud_id(access_token)
except Exception as e:
logging.error(f"Failed to get cloud ID: {e}")
return Response("Failed to get cloud ID. Please try again.", status=200)
# Use the access token to fetch projects from Jira
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
response = requests.get(f"https://api.atlassian.com/ex/jira/{cloud_id}/rest/api/3/project", headers=headers)
if response.status_code != 200:
logging.error(f"Failed to fetch projects: {response.text}")
return Response("Failed to fetch projects. Please try again.", status=200)
projects = response.json()
project_list = "\n".join([f"{project['key']}: {project['name']}" for project in projects])
client.chat_postMessage(channel=user_id, text=f"Here are your projects:\n{project_list}")
return Response(), 200
@app.route('/report', methods=['POST'])
def generate_report():
data = request.form
user_id = data.get('user_id')
# Fetch the selected project from the database
c.execute('SELECT project_key FROM selected_project WHERE user_id = ?', (user_id,))
result = c.fetchone()
if result is None:
return Response("You need to select a project first. Use /selectProject <project_key>.", status=200)
project_key = result[0]
# Fetch the access token from the database
c.execute('SELECT access_token FROM tokens WHERE user_id = ?', (user_id,))
result = c.fetchone()
if result is None:
return Response("You need to log in first. Use /login.", status=200)
access_token = result[0]
# Fetch cloud ID
try:
cloud_id = get_cloud_id(access_token)
except Exception as e:
logging.error(f"Failed to get cloud ID: {e}")
return Response("Failed to get cloud ID. Please try again.", status=200)
# Use the access token to fetch sprint information from Jira
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
# Get board ID for the project
response = requests.get(f"https://api.atlassian.com/ex/jira/{cloud_id}/rest/agile/1.0/board?projectKeyOrId={project_key}", headers=headers)
if response.status_code != 200:
logging.error(f"Failed to fetch boards: {response.text}")
if response.status_code == 401:
return Response("Unauthorized access. Please re-authenticate using /login.", status=200)
return Response("Failed to fetch boards. Please try again.", status=200)
boards = response.json().get('values', [])
if not boards:
return Response(f"No boards found for project {project_key}.", status=200)
board_id = boards[0]['id']
# Get current sprint ID
response = requests.get(f"https://api.atlassian.com/ex/jira/{cloud_id}/rest/agile/1.0/board/{board_id}/sprint?state=active", headers=headers)
if response.status_code != 200:
logging.error(f"Failed to fetch sprints: {response.text}")
if response.status_code == 401:
return Response("Unauthorized access. Please re-authenticate using /login.", status=200)
return Response("Failed to fetch sprints. Please try again.", status=200)
sprints = response.json().get('values', [])
if not sprints:
return Response(f"No active sprints found for board {board_id}.", status=200)
sprint_id = sprints[0]['id']
# Get issues in the current sprint
response = requests.get(f"https://api.atlassian.com/ex/jira/{cloud_id}/rest/agile/1.0/sprint/{sprint_id}/issue", headers=headers)
if response.status_code != 200:
logging.error(f"Failed to fetch issues: {response.text}")
if response.status_code == 401:
return Response("Unauthorized access. Please re-authenticate using /login.", status=200)
return Response("Failed to fetch issues. Please try again.", status=200)
issues = response.json().get('issues', [])
# Generate report
report = f"Daily Report for Sprint {sprint_id} in Project {project_key}:\n"
for issue in issues:
report += f"- {issue['key']}: {issue['fields']['summary']} (Status: {issue['fields']['status']['name']})\n"
client.chat_postMessage(channel=user_id, text=report)
return Response(), 200
the route /login and /listprojects work perfectly. But the /report doesn’t.
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.atlassian.com:443
DEBUG:urllib3.connectionpool:https://api.atlassian.com:443 "GET /ex/jira/2e1b18bd-d8f4-4086-9538-2850e79aa295/rest/agile/1.0/board?projectKeyOrId=PMAAS HTTP/1.1" 401 59
ERROR:root:Failed to fetch boards: {"code":401,"message":"Unauthorized; scope does not match"}
How can I solve that?