External auth error

Alright, I’ve been stuck with this error for awhile now while noodling with external auth module and Discord’s OAuth2 API:

could not retrieve access token from the provider

I found this older thread which points me to this nice common problems guide that offers:

  1. Ensure the client secret has been set using the configure providers CLI command.
  2. Confirm the exchange URL is correct in the manifest.yml file.

For 1., I’ve confirmed and re-confirmed that I have the secret set appropriately.

For 2., I can see from Discord’s OAuth2 URLs documentation that the token URL is:

https://discord.com/api/oauth2/token

The relevant parts of my manifest.yml are as follows:

providers:
  auth:
    - key: discord
      name: Discord
      scopes:
        - 'identify'
        - 'email'
      type: oauth2
      clientId: '908442509259178044'
      remotes:
        - discord-oauth
      bearerMethod: form-encoded
      actions:
        authorization:
          remote: discord-oauth
          path: /oauth2/authorize
        exchange:
          remote: discord-oauth
          path: /oauth2/token
          resolvers:
            accessTokenExpires: expires_in
        revokeToken:
          remote: discord-oauth
          path: /oauth2/token/revoke
        retrieveProfile:
          remote: discord-oauth
          path: /me
          resolvers:
            id: id
            displayName: username
remotes:
  - key: discord-oauth
    baseUrl: https://discord.com/api
  external:
    fetch:
      backend:
        - 'https://discord.com/api'

So I’m leading myself to believe that I have the exchange URL constructed properly…

Any thoughts on what else I could be missing? It is really hard to debug what could be going wrong because I don’t have any sense of what is going on under the hood. It would be nice if I could really noisy errors while I was in development mode.


Below are some other things I’m expanding on to make sure my understanding of the setup is correct

Discord’s Access Token Response shows a payload:

{
  "access_token": "6qrZcUqja7812RVdnEKjpzOL4CvHBFG",
  "token_type": "Bearer",
  "expires_in": 604800,
  "refresh_token": "D43f5y0ahjqew82jZ4NViEr2YafMKhue",
  "scope": "identify"
}

Since the default for accessTokenExpires is expires, I’ve changed the resolver to look for expires_in:

exchange:
  remote: discord-oauth
   path: /oauth2/token
    resolvers:
      accessTokenExpires: expires_in
3 Likes

Just a quick observation, the referenced Discord docs state that “the token and token revocation URLs will only accept a content type of application/x-www-form-urlencoded, you seem to be using authentication bearerMethod: authorization-header rather than bearerMethod: form-encoded though?

1 Like

Ha. I just edited my original post. I originally had form-encoded but had delved into the “try changing everything a little bit at least once” debugging phase and this was one of the bits I’d flipped but hadn’t reset to my original “this appears to be correct” code.

1 Like

From a quick glance at your config, there may be an issue with the way you have the path configured.
The path is joined onto the baseUrl like a browser would in a href field, so its currently doing a POST /oauth2/token.

Can you try removing the leading / in the path of your exchange definition, eg

exchange:
  remote: discord-oauth
  path: oauth2/token
...
remotes:
  - key: discord-oauth
    baseUrl: https://discord.com/api

The details on how it joins are detailed in the runtime API documentation, but not in the manifest section unfortunately…

2 Likes

Ah, I see it:

Relative path from the remote specified in withProvider.

If the url parameter starts with a /, the remote baseUrl path is ignored.
1 Like