Forge External OAuth2: debugging & fixing not possible at all!

In Postman I have an external BearerOauth2-request and a related, authenticated API-request which both run fine!

While transfering these requests to Forge using External OAuth2 with bearerMethod “form-encoded” I experience the following:

$> forge lint: no errors
$> forge deploy: no errors
$> forge tunnel: “invalid manifest”-error in red, invoked function “index.runApp”
Deployed App on Development-Site in Frontend: Function with handler “index.runApp” was not found.

It seems the Forge DX is somekind of ambiguous.

see Cli screenshot running $> forge deploy:
image
no error about the runApp()-function in src/index.jsx

see App screenshot from development site:

Please find “manifest.yml” and the “index.jsx” below.

  1. see “manifest.yml”:

app:
id: ari:cloud:ecosystem::app/370fd8cd-3193-45a3-9a05-2a1852bb4b24
modules:
jira:issueGlance:
- key:
function: main
title: Evaluation
description: Evaluation
label: Evaluation
function:
- key: main
handler: index.runApp
providers:
auth:
- external-server
providers:
auth:
- key: external-server
name: “”
type: oauth2
scopes:
- “api”
clientId: “”
bearerMethod:
type: form-encoded
parameter: “token”
actions:
authorization:
remote: api-server
path: /oauth/authorize
exchange:
remote: api-server
path: /oauth/token
resolvers:
accessTokenExpires: expires_in
retrieveProfile:
remote: api-server
path: /api/User/
resolvers:
id: Id
displayName: Shortname
remotes:

  • key: api-server
    baseUrl: “https://:”
    permissions:
    scopes:
    • read:jira-work
      external:
      fetch:
      backend:
      • https://.atlassian.net/
      • https://:/
  1. see “src/index.jsx”:

import api from “@forge/api”;
import {
render,
IssueGlance,
Fragment,
useState,
Code,
} from “@forge/ui”;

const App = () => {
const [data] = useState(async () => {
console.log(data);

const response = await api
  .asApp()
  .withProvider("external-server", "api-server")
  .fetch("/api/User/");

return await response.json();

});

return (

<Code text={JSON.stringify(data, null, 2)} language=“json”>

);
};

export const runApp = render(



);

These are the key articles I used while trying to adapt to my needs, despite the forge developer documentaions:
https://developer.atlassian.com/platform/forge/use-an-external-oauth-2.0-api-with-fetch/
and New: Forge External Authentication Makes Outbound OAuth Easy - Atlassian Developer Blog

What exactly is the problem?
Is it the “manifest.yml”?
Is it the “src/index.jsx”?
Is it the docker container, because “forge tunnel” linting is different from using “forge lint”?
Is it the “forge tunnel” npm package according to the App errorr?
Why is “forge logs” not showing anything at all?

This way I can’t seem to debug and fix this!

Please help, Atlassian and support to make Forge DX a breeze!
Thank you very much!

Cheers, Marco

I noticed a couple of things but not sure if they’re causing the issue:

  • The key value for the jira:issueGlance module is null (although this should have been picked up by the linter - perhaps you just removed it from your example?)
  • It looks like you have the baseUrl as “https://:”. What are you trying to do here?

Hi Adam,

here are my files using the preformatted text option to preserve all chars.

I tried adding more permission scopes and updated the external fetch backend to a domain, instead of a URL - The behaviour is still the same: No Linting errors running forge lint. No error running forge install --upgrade. Invalid manifest when running forge deploy. Function index.runApp not found in Frontend.

Is there a JSON schema file to validate the manifest.yml against in my IDE?
It currently seems like a blackbox to me. I cannot judge if it is a structural error in manifest, or an error related to values in manifest for the 3rd party oauth mechanism, if it’s an error in the scope and the registering of the js functions, the js functions itself or the api call within or is it a potential bug in forge?
The current error messages provided by forge env in this context are not very helpful.

Please help!

manifest.yml

app:
  id: ari:cloud:ecosystem::app/370fd8cd-3193-45a3-9a05-2a1852bb4b24
modules:
  jira:issueGlance:
    - key: ejIssueGlance
      function: main
      title: "ej"
      description: "ej"
      label: "ej"
  function:
    - key: main
      handler: index.runApp
      providers:
        auth:
          - ej
providers:
  auth:
    - key: ej
      name: "ej name"
      type: oauth2
      scopes:
        - "api"
      clientId: "123"
      bearerMethod:
        type: form-encoded
        parameter: "token"
      actions:
        authorization:
          remote: ej-server
          path: /easy/app/oauth/authorize
        exchange:
          remote: ej-server
          path: /easy/app/oauth/token
        retrieveProfile:
          remote: ej-server
          path: /easy/app/api/User/
          resolvers:
            id: Id
            displayName: Shortname
remotes:
  - key: ej-server
    baseUrl: "https://foo.bar.com:8888"
permissions:
  scopes:
    - write:jira-work
    - read:jira-user
    - manage:jira-webhook
  external:
    fetch:
      backend:
        - "foo.bar.com"

src/index.jsx

import ForgeUI, {
  render,
  IssueGlance,
  Fragment,
  useState,
  Code,
} from "@forge/ui";
import api from "@forge/api";

const App = () => {
  const [data] = useState(async () => {
    console.log(data);

    const response = await api
      .asApp()
      .withProvider("ej", "ej-server")
      .fetch("/easy/app/api/User");

    return await response.json();
  });

  return (
    <Fragment>
      <Code text={JSON.stringify(data, null, 2)} language="json"></Code>
    </Fragment>
  );
};

export const runApp = render(
  <IssueGlance>
    <App />
  </IssueGlance>
);

$> forge tunnel:
image

dev site frontend:

Hi Adam, thank you very much for pointing to the module key and the baseURL mispellings.
But these issues simply occured while inserting my files as plain-text inside the post and the re-formatting of < placeholders > inside the files. I don’t think that these were causing any trouble.
Seems like using pre-formatted text works way better for inserting sourcecode. King regards, Marco

Thanks for that, much easier to read. There doesn’t seem to be any problem with your manifest. I think that error might be misleading.

I tried out your sample code and the app deployed and installed fine. Interacting with it, it failed after the user consent screen when it tried to send me to the remote’s authorize Url. That failed because obviously https://foo.bar.com:8888/easy/app/oauth/authorize doesn’t exist.

I assume you’re actually using a different remote baseUrl (and clientId etc) for your app?

Hi Adam,

thank you for getting back to me! Yes, actually I use another remote baseUrl, which I can’t share here.
What helped in getting past the “invalid manifest”-error message, I added a small piece of remotes in the manifest in the providers auth section, while keeping the remotes key+baseUrl:

      clientId: "123"
      remotes:
        - ej-server
      bearerMethod:
        type: form-encoded
        parameter: "token"

Well, going further now, could you please ensure that I choose the right path to implement OAuth2 Flow for “client_credentials”?

With your help I got past the “invalid manifest”-error, which feels really good! But the next error is around the corner: “fetch failed … no credentials previously requested”.

I assume there is something wrong with the bearerMethod-setting or more probable with the js-fetch request itself? Looking a step further, does retrieveProfile interfere in this context?

According to the working Postman-request the 3rd party API requires a POST with “x-www-form-urlencoded” and passing params in request body. Please see details here:

image

Can you please confirm that these are the corresponding bearerMethod-settings for the kind of request I am trying to implement? By the way, during Forge app deployment the CLI already asked for a client_secret.

Seems more blackboxing going on here… Altassian, please shed light!

@MarcoSiegl,

The Forge external auth module does not support client credentials flow.

1 Like

Hi @ibuchanan, thank you for you quick response!
Didn’t expect to read that from a company like Atlassian. :umbrella:

But anyway, what kind of information about your in Forge supported OAuth2 Flows do I have to give our API provider in order what they can do to make this work with Forge?

These are the currently supported OAuth flows by the API provider:

Might the “bearer (http, Bearer)” (see screenshot) a supported option in Forge and what preps are required to beeing able use that OAuth-Type in Forge?

Thanks for getting back to me, hopefully with better news!

@MarcoSiegl,

A screenshot is a really poor auth spec so I’m guessing that works the way Open API describes it, using Authorization: Bearer <token>. If that’s true, you can use what Forge calls Basic authentication. Despite what most developers would expect, that allows your client to add options to your HTTP request, rather than construct the auth headers programmatically. So, if my prior assumptions hold, here’s some example JavaScript:

const token = "abc123"
const options = {
  headers: {
    Authorization: `Bearer ${token}`
  }
};
const result = await fetch(
  "https://example.net/",
  options
);
const status = result.status;
1 Like

@ibuchanan,
thank you for pointing to basic authentication as the way to go, which I sure will give a try!
Well, seems the only option for now :face_with_monocle:

I will report here about the progress!
Cheers, Marco

Hi @ibuchanan,

using the “Fetch-API only”-approach does work now (!) to externally connect and consume the REST API with the “clients_credentials” OAuth2-Flow! Thanks for pointing into the right direction, but sad, that it took a rather long time to realize that the Atlassian implementation to OAuth is not sufficient. Please try to add a hint for “client_credentials” in your Forge-Documentation pages to point a little earlier in this context to the Fetch-API approach:

I did setup a nested request sequence to first get the OAuth2 bearer access_token JSON and to include that received auth token in all nested API kind of regular JSON requests! A little tricker was the URL encoding of the particular OAuth2-Flow which required “application/x-www-form-urlencoded” to pass the client credentials. That was far different from what Postman was outputting when using “node.js Fetch”-export option.

Well, what I am still not very happy with is the missing JSON schema auto-complete in my IDE and the debugging capabilites in Forge, so if anyone still having trouble to troubleshoot, these links have helped me a lot in debugging & developing forge:

But still, where can I find the JSON schema files to enable auto-completion for the “manifest.yml”?
Is there some kind of file you can provide?

@MarcoSiegl,

I logged an issue for the client credentials flow:
https://ecosystem.atlassian.net/browse/FRGE-1167

For the manifest autocompletion issue, please start a new thread.

1 Like