Hello There! I’m new in Forge development.
I’m trying to build an app who’s calls Google API and in the redirect URL i got:
RequestValidationError: Schema validation error
After that, i’ve follow the documentation https://developer.atlassian.com/platform/forge/use-an-external-oauth-2.0-api-with-fetch/
And my manifest looks like this now:
modules:
'jira:issuePanel':
- key: gcalendar-hello-world-panel
function: main
title: Gcalendarv4
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
function:
- key: main
handler: index.run
providers:
auth:
- google
app:
id: my app id
remotes:
- key: google-apis
baseUrl: https://www.googleapis.com
- key: google-account
baseUrl: https://accounts.google.com
- key: google-oauth
baseUrl: https://oauth2.googleapis.com
permissions:
scopes:
- 'read:jira-work'
- 'write:jira-work'
external:
fetch:
backend:
- 'https://www.googleapis.com'
- 'https://oauth2.googleapis.com'
- 'https://accounts.google.com'
Providers:
auth:
- key: google
name: Google
scopes:
- 'profile'
- 'https://www.googleapis.com/auth/userinfo.email'
type: oauth2
clientId: (my id) apps.googleusercontent.com
remotes:
- google-apis
bearerMethod: authorization-header
actions:
authorization:
remote: google-account
path: /o/oauth2/v2/auth
exchange:
remote: google-oauth
path: /token
revokeToken:
remote: google-oauth
path: /revoke
retrieveProfile:
remote: google-apis
path: /userinfo/v2/me
resolvers:
id: id
displayName: email
avatarUrl: picture
when trying to deploy i got this error
13:0 error app should NOT have additional property 'remotes' valid-document-required
Anyone if can help me would appreciate it.
Thanks
Ruben
@RubnOviedo,
I think you might be dealing with a compound problem. With multiple things going wrong, it’s hard to tell where to focus. To start, Forge Remotes should not be nested inside the app
node, they are a top-level option. Unindent them please.
Hello @ibuchanan, first, thank you for your reply
Have to look like this?
modules:
'jira:issuePanel':
- key: gcalendar-hello-world-panel
function: main
title: Gcalendarv4
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
function:
- key: main
handler: index.run
providers:
auth:
- google
app:
id: ari:cloud:ecosystem::app/d5467e22-85b1-4542-99f4-3bf7af3d3b74
permissions:
scopes:
- 'read:jira-work'
- 'write:jira-work'
external:
fetch:
backend:
- 'https://www.googleapis.com'
- 'https://oauth2.googleapis.com'
- 'https://accounts.google.com'
Providers:
auth:
key: google
name: Google
scopes:
- 'profile'
- 'https://www.googleapis.com/auth/userinfo.email'
type: oauth2
clientId: myclientid
Again, sorry i’m too noob for this.
@RubnOviedo,
What I meant was change this:
app:
id: my app id
remotes:
- key: google-apis
baseUrl: https://www.googleapis.com
- key: google-account
baseUrl: https://accounts.google.com
- key: google-oauth
baseUrl: https://oauth2.googleapis.com
To this:
app:
id: my app id
remotes:
- key: google-apis
baseUrl: https://www.googleapis.com
- key: google-account
baseUrl: https://accounts.google.com
- key: google-oauth
baseUrl: https://oauth2.googleapis.com
In YAML, whitespace matters. It seems that you have simply removed them (and some other things). Or is that a copy/paste error?
Perhaps the easiest thing would be to copy/paste the Google example from here: https://developer.atlassian.com/platform/forge/manifest-reference/providers/#example
Be sure to keep your existing modules
and app
sections.
The let us know what errors you get.
1 Like
Now perfectly understand the whitespace and now able to deploy the app.
modules:
'jira:issuePanel':
- key: gcalendar-hello-world-panel
function: main
title: Gcalendarv4
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
function:
- key: main
handler: index.run
app:
id: myid
remotes:
- key: google-apis
baseUrl: https://www.googleapis.com
- key: google-account
baseUrl: https://accounts.google.com
- key: google-oauth
baseUrl: https://oauth2.googleapis.com
permissions:
scopes:
- 'read:jira-work'
- 'write:jira-work'
external:
fetch:
backend:
- 'https://www.googleapis.com'
- 'https://oauth2.googleapis.com'
- 'https://accounts.google.com'
providers:
auth:
- key: google
name: Google
scopes:
- 'profile'
- 'https://www.googleapis.com/auth/userinfo.email'
type: oauth2
clientId: myid
remotes:
- google-apis
bearerMethod: authorization-header
actions:
authorization:
remote: google-account
path: /o/oauth2/v2/auth
exchange:
remote: google-oauth
path: /token
revokeToken:
remote: google-oauth
path: /revoke
retrieveProfile:
remote: google-apis
path: /userinfo/v2/me
resolvers:
id: id
displayName: email
avatarUrl: picture
but the Schema validation error persist.
![image](https://global.discourse-cdn.com/atlassiandeveloper/original/3X/a/a/aa4f5265430ac1208fe94659e4dd8ef9a9ac552e.png)
Maybe is something wrong with my app?
import ForgeUI, { render, IssuePanel, Text, Button, useProductContext, useState } from '@forge/ui';
import api, { route } from "@forge/api";
const App = () => {
const { extensionContext: { issueKey } } = useProductContext();
const [transferStatus, setTransferStatus] = useState('');
const [authUrl, setAuthUrl] = useState('');
const clientId = 'myid';
const redirectUrl = 'https://id.atlassian.com/outboundAuth/finish';
const getAuthorizationUrl = () => {
const authEndpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
const scope = 'https://www.googleapis.com/auth/calendar';
const responseType = 'code';
const urlParams = new URLSearchParams({
client_id: clientId,
redirect_uri: redirectUrl,
scope: scope,
response_type: responseType,
});
const authUrl = `${authEndpoint}?${urlParams.toString()}`;
return authUrl;
};
const moveToGoogleCalendar = async () => {
try {
// Fetch issue details from Jira
const response = await api.asApp().requestJira(route`/rest/api/3/issue/${issueKey}`);
const issueData = await response.json();
if (!issueData) {
throw new Error('Failed to fetch issue details');
}
// Construct the event data for Google Calendar
const eventData = {
summary: issueData.fields?.summary,
description: issueData.fields?.description,
start: {
date: issueData.fields?.duedate, // Use date instead of dateTime
},
end: {
date: issueData.fields?.duedate, // Use date instead of dateTime
},
};
// Get the authorization URL
const url = getAuthorizationUrl();
setTransferStatus('Please authorize the app by copying the following URL into your browser:');
setAuthUrl(url);
} catch (error) {
console.error('Error:', error);
setTransferStatus('Transfer failed. Please try again.');
}
};
return (
<IssuePanel>
<Text content={`Current issue key: ${issueKey}`} />
<Button text="Move to Google Calendar" onClick={moveToGoogleCalendar} />
<Text content={transferStatus} />
{authUrl && (
<Text content={authUrl} />
)}
</IssuePanel>
);
};
export const run = render(<App />);
Really appreciate your help at this point @ibuchanan
Please if anyone can help me
@RubnOviedo,
It looks like your code is trying perform part of the OAuth flow. Like, in your UI code, you have the authUrl
as if it were a hyperlink. The error you are getting is probably because that flow has to be paired with some back-end API exchanges. The point of these auth
providers is to abstract all of that away.
Before trying to add your own calendar logic, I think you should make sure the example code for calling an API (with the google external auth provider) works in your app. Then, you’ll probably want to replace the example google.fetch('/userinfo/v2/me')
with the more elaborate call to POST
a calendar item.