Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

OAuth on Forge App with Tempo.io

Christian Seidel
I'm New Here
I'm New Here
Those new to the Atlassian Community have posted less than three times. Give them a warm welcome!
May 6, 2026

TLDR:
https://id.atlassian.com/outboundAuth/finish always returns 400 with "RequestValidationError: Schema validation error" body.


Story:

We are migrating from Jira Server to Jira Cloud and need to migrate an application we wrote for Jira Server to Jira Cloud Forge and want to use OAuth mechanism to create worklogs in Tempo from Forge App.

I installed Tempo Core as well as Tempo Timesheets on our instance longer time ago. Today i did update them to latest versions. (Tempo Core (latest (12.2.0)) Tempo Timesheets (latest (10.1.0)).

I created an OAuth2 application in Tempo with Redirect URL: https://id.atlassian.com/outboundAuth/finish

I setup our app (that was working with Bearer Tokens before for test purposes and now rewrote Auth to OAuth) with that (redacted) manifest:

modules:
jira:globalPage:
- key: abwesenheiten-global
resource: main
resolver:
function: resolver
title: Abwesenheiten
icon: resource:main;icons/x.png
function:
- key: resolver
handler: index.handler
providers:
auth:
- tempo-oauth

resources:
- key: main
path: static/<redacted>/build

remotes:
- key: jira-base
baseUrl: https://<redacted>.atlassian.net
- key: tempo-api
baseUrl: https://api.eu.tempo.io

providers:
auth:
- key: tempo-oauth
name: Tempo
type: oauth2
scopes:
- worklogs:write
clientId: <redacted>
remotes:
- tempo-api
bearerMethod: authorization-header
actions:
authorization:
remote: tempo-api
path: /oauth/authorize/redirect
queryParameters:
jira_url: https://<redacted>.atlassian.net
exchange:
remote: tempo-api
path: /oauth/token/
refreshToken:
remote: tempo-api
path: /oauth/token/
revokeToken:
remote: tempo-api
path: /oauth/revoke_token/
retrieveProfile:
remote: jira-base
path: /rest/api/3/myself
method: GET
resolvers:
id: accountId
displayName: displayName

permissions:
scopes:
- storage:app
- read:jira-user
- read:jira-work
- read:field:jira
- read:field-configuration:jira
- read:issue:jira
- write:jira-work
- write:issue:jira
- delete:issue:jira
external:
fetch:
backend:
- remote: jira-base
- remote: tempo-api

app:
runtime:
name: nodejs22.x
memoryMB: 256
architecture: arm64
id: ari:cloud:ecosystem::app/<redacted>

I also set provider secret via forge providers configure -e development

There is also some Code to trigger consent screen:

resolver.define("checkTempoConnection", async (_req) => {
const tempoProvider = api.asUser().withProvider("tempo-oauth", "tempo-api");
const hasCredentials = await tempoProvider.hasCredentials();
if (!hasCredentials) {
await tempoProvider.requestCredentials();
}
return { connected: true };
});

After klicking on Configure Access and doing oAuth dance i finally land on this

698e6296-fa48-44c7-bf5e-3a70c01d2f29.png

But after clicking on "Onwards!" i only get a 400 from https://id.atlassian.com/outboundAuth/finish with Message 

RequestValidationError: Schema validation error

and i got no idea what is wrong.

1 answer

0 votes
Jeroen Poismans
Community Champion
May 7, 2026

Hi and welcome to the community!

Since this question is related to Forge and app development, have you tried raising this exact post in the Developer Community?

You might have better luck there:

https://community.developer.atlassian.com/

Suggest an answer

Log in or Sign up to answer