Forge External Authentication and Azure API

Hi everyone,
I’m trying to implement external calls from the Forge plugin to Azure Active Directory using oauth2. I have registered a new client within Azure AD and got the client ID and the client secret, and added the redirect URI ‘https://myid.atlassian.com/outboundAuth/finish’. I have set the client ID in the providers.auth section of the manifest.yml file and set the client secret by running ‘forge providers configure’ command in CLI.

Here’ s my manifest file:

modules:
  webtrigger:
    - key: temporary-development-webtrigger
      function: main
  function:
    - key: main
      handler: index.run
      providers:
        auth:
          - azure
app:
  id: ari:cloud:ecosystem::app/0a4b3acc-6bb2-42e3-8053-d6e4d7357e7f
providers:
  auth:
    - key: azure
      name: MSAzure
      scopes:
        - openid
        - profile
        - email
        - https://login.microsoftonline.com/myTenantID/oauth2/v2.0/authorize
        - https://login.microsoftonline.com/myTenantID/oauth2/v2.0/token
        - https://graph.microsoft.com/oidc/userinfo
      type: oauth2
      clientId: myClientID
      remotes:
        - azure-login
        - azure-graph
      bearerMethod: authorization-header
      actions:
        authorization:
          remote: azure-login
          path: /myTenantID/oauth2/v2.0/authorize
        exchange:
          remote: azure-login
          path: /myTenantID/oauth2/v2.0/token
        retrieveProfile:
          remote: azure-graph
          path: /oidc/userinfo
          resolvers:
            id: sub
            displayName: email
remotes:
  - key: azure-login
    baseUrl: https://login.microsoftonline.com
  - key: azure-graph
    baseUrl: https://graph.microsoft.com
permissions:
  scopes:
    - read:user:jira
    - read:application-role:jira
    - read:avatar:jira
    - read:group:jira
  external:
    fetch:
      backend:
        - 'https://login.microsoftonline.com'
        - 'https://graph.microsoft.com'

here’s my API call:

 const azure = api.asUser().withProvider('azure', 'azure-login')

    console.log('azure.hasCredentials() = ' + await azure.hasCredentials());
    if (!await azure.hasCredentials()) {
        await azure.requestCredentials()
    }

I’ve tried a lot of different settings and I’m still getting such an error:

INFO    2022-05-19T09:23:32.754Z 155cf041-80f1-4f5b-a1d1-2a85b4e0c5c2 azure.hasCredentials() = false
ERROR   2022-05-19T09:23:32.756Z 155cf041-80f1-4f5b-a1d1-2a85b4e0c5c2 {
  message: 'Authentication required',
  name: 'NEEDS_AUTHENTICATION_ERR',
  stack: ''
}

I also can get a list of Azure endpoints and some settings, that could be useful from this URL - ‘https://login.microsoftonline.com/myTenantID/v2.0/.well-known/openid-configuration’ :

{
  "token_endpoint": "https://login.microsoftonline.com/myTenantID/oauth2/v2.0/token",
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "private_key_jwt",
    "client_secret_basic"
  ],
  "jwks_uri": "https://login.microsoftonline.com/myTenantID/discovery/v2.0/keys",
  "response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  "subject_types_supported": [
    "pairwise"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "response_types_supported": [
    "code",
    "id_token",
    "code id_token",
    "id_token token"
  ],
  "scopes_supported": [
    "openid",
    "profile",
    "email",
    "offline_access"
  ],
  "issuer": "https://login.microsoftonline.com/myTenantID/v2.0",
  "request_uri_parameter_supported": false,
  "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo",
  "authorization_endpoint": "https://login.microsoftonline.com/myTenantID/oauth2/v2.0/authorize",
  "device_authorization_endpoint": "https://login.microsoftonline.com/myTenantID/oauth2/v2.0/devicecode",
  "http_logout_supported": true,
  "frontchannel_logout_supported": true,
  "end_session_endpoint": "https://login.microsoftonline.com/myTenantID/oauth2/v2.0/logout",
  "claims_supported": [
    "sub",
    "iss",
    "cloud_instance_name",
    "cloud_instance_host_name",
    "cloud_graph_host_name",
    "msgraph_host",
    "aud",
    "exp",
    "iat",
    "auth_time",
    "acr",
    "nonce",
    "preferred_username",
    "name",
    "tid",
    "ver",
    "at_hash",
    "c_hash",
    "email"
  ],
  "kerberos_endpoint": "https://login.microsoftonline.com/myTenantID/kerberos",
  "tenant_region_scope": "EU",
  "cloud_instance_name": "microsoftonline.com",
  "cloud_graph_host_name": "graph.windows.net",
  "msgraph_host": "graph.microsoft.com",
  "rbac_url": "https://pas.windows.net"
}

Guys, what am I doing wrong?
I’m pretty new to Jira and Node.js, thus any kind of help would be really helpful.

1 Like

Hi @SergeyKhalin , thanks for trying out forge and external authentication!

The error you are seeing the console is expected and is the error that triggers the frontend to render the button.
What are you seeing in the frontend?

If I had to guess, it might be that you need to run forge deploy.
Unfortunately you need to deploy any changes to providers and modules before running forge tunnel for it to take effect.

Hi @MichaelCooper , thanks for the reply!

What I was trying to do is to create a function running in the background and triggered by a web-trigger (for debugging) or by a scheduled trigger for production. So there’s no frontend implementation. Do I need it anyway? Btw, both triggers work fine and successfully invoke the function.

While debugging I wasn’t using the tunneling, instead, I just retrieved logs with the forge logs command. Now I tried the tunneling and the problem is still the same((

INFO    08:34:55.346  d99582db5ea0c092  azure.hasCredentials() = false
ERROR   08:34:55.349  d99582db5ea0c092  [NEEDS_AUTHENTICATION_ERR: Authentication required] {
  serviceKey: 'azure'
}

Do you have any ideas what else could be wrong?

Ah, The external authentication API only works under asUser, which requires an authenticated user to invoke the forge function.
Using forge from a scheduled trigger will not have an authenticated user, so will always have no credentials.

I would encourage you to raise a feature request for allowing external authentication with asApp.

Hi @MichaelCooper , thanks for the advice!
I raised the feature request. I’ll share any details when I get the response.

@MichaelCooper have you a working example of using Azure AD with forge? I’m basically trying to get the “asUser” working and getting the same “Authentication required”.

Is there any way to get better error/debug info? forge logs doesnt give any clues.

Also I’m suspect about the retrieveProfile for Azure AD. The forge doco says its mandatory but when running client_credentials you dont get access to a user profile, so not even sure if its used or not. We really need an example like the google one, for Azure AD and also maybe slack.

I’ve logged this with support but they said they dont help development and to log something in community.

Thanks.