[GH-ISSUE #1904] [Bug]: GoCardless API responds with 401s #49851

Closed
opened 2026-04-30 11:42:38 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @toebbel on GitHub (Nov 13, 2023).
Original GitHub issue: https://github.com/actualbudget/actual/issues/1904

Verified issue does not already exist?

  • I have searched and found no existing issue

What happened?

I have used Nordigen / GoCardless for a while now and it worked smoothly.
This morning it stopped working. Steps I've done so far:

  • unlink account , trying to re-link (see api failing)
  • create new secrets in GoCardless Dashboard & setting them in actual UI
  • create new secrets in GoCardless without IP restriction & setting them in actual UI
  • use GoCardless secrets in Insomnia (Postman-like tool) to see if they work; I can generate an access token successfully
  • verified GoCardless status page, no issues reported there
  • tested to set credentials via Safari & Chrome

The error I see in the UI:
Screenshot 2023-11-13 at 17 39 06

The UI to set secrets:
Screenshot 2023-11-13 at 17 39 12

What error did you receive?

logs from my fly.io instance

2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]Error /gocardless/get-banks h [AxiosError]: Request failed with status code 401
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    at re (file:///app/node_modules/nordigen-node/dist/index.esm.js:13:914)
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    method: 'get',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    url: URL {
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      href: 'https://ob.gocardless.com/api/v2/institutions/?country=SE',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      origin: 'https://ob.gocardless.com',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      protocol: 'https:',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      username: '',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      password: '',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      host: 'ob.gocardless.com',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      hostname: 'ob.gocardless.com',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      port: '',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      pathname: '/api/v2/institutions/',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      search: '?country=SE',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      searchParams: URLSearchParams { 'country' => 'SE' },
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      hash: ''
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    },
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    data: undefined
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]  },
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    _header: 'GET /api/v2/institutions/?country=SE HTTP/1.1\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'Accept: application/json\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'Content-Type: application/json\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'User-Agent: Nordigen-Node-v2\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'Accept-Encoding: gzip, compress, deflate, br\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'Host: ob.gocardless.com\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'Connection: close\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      '\r\n',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    _keepAliveTimeout: 0,
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    _onPendingData: [Function: nop],
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      responseUrl: 'https://ob.gocardless.com/api/v2/institutions/?country=SE',
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]  response: {
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    status: 401,
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    statusText: 'Unauthorized',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    headers: T [AxiosHeaders] {
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      date: 'Mon, 13 Nov 2023 16:30:19 GMT',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'content-type': 'application/json',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'content-length': '110',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      connection: 'close',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      server: 'nginx',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'www-authenticate': 'Bearer realm="api"',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      vary: 'Accept, Accept-Language, Cookie',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      allow: 'GET, HEAD, OPTIONS',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'x-frame-options': 'DENY',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'content-language': 'en',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'x-content-type-options': 'nosniff',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      'referrer-policy': 'same-origin'
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    },
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    request: <ref *1> ClientRequest {
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      socket: [TLSSocket],
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      _header: 'GET /api/v2/institutions/?country=SE HTTP/1.1\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]        'Accept: application/json\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]        'Content-Type: application/json\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]        'User-Agent: Nordigen-Node-v2\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]        'Accept-Encoding: gzip, compress, deflate, br\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]        'Host: ob.gocardless.com\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]        'Connection: close\r\n' +
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]        '\r\n',
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      path: '/api/v2/institutions/?country=SE',
...
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    },
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    data: {
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      summary: 'Authentication failed',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      detail: 'Authentication credentials were not provided.',
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]      status_code: 401
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]    }
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]  }
2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]}

Where are you hosting Actual?

Fly.io

What browsers are you seeing the problem on?

Chrome, Safari

Operating System

Mac OSX

Originally created by @toebbel on GitHub (Nov 13, 2023). Original GitHub issue: https://github.com/actualbudget/actual/issues/1904 ### Verified issue does not already exist? - [X] I have searched and found no existing issue ### What happened? I have used Nordigen / GoCardless for a while now and it worked smoothly. This morning it stopped working. Steps I've done so far: - unlink account , trying to re-link (see api failing) - create new secrets in GoCardless Dashboard & setting them in actual UI - create new secrets in GoCardless without IP restriction & setting them in actual UI - use GoCardless secrets in Insomnia (Postman-like tool) to see if they work; I can generate an access token successfully - verified [GoCardless status page](http://gocardless-status.com), no issues reported there - tested to set credentials via Safari & Chrome The error I see in the UI: <img width="515" alt="Screenshot 2023-11-13 at 17 39 06" src="https://github.com/actualbudget/actual/assets/779528/33165936-23b1-4146-8077-112e174c8bf6"> The UI to set secrets: <img width="512" alt="Screenshot 2023-11-13 at 17 39 12" src="https://github.com/actualbudget/actual/assets/779528/d4f2f7f0-098c-420a-8def-f4e263dc7151"> ### What error did you receive? logs from my fly.io instance ``` 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]Error /gocardless/get-banks h [AxiosError]: Request failed with status code 401 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] at re (file:///app/node_modules/nordigen-node/dist/index.esm.js:13:914) ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] method: 'get', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] url: URL { 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] href: 'https://ob.gocardless.com/api/v2/institutions/?country=SE', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] origin: 'https://ob.gocardless.com', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] protocol: 'https:', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] username: '', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] password: '', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] host: 'ob.gocardless.com', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] hostname: 'ob.gocardless.com', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] port: '', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] pathname: '/api/v2/institutions/', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] search: '?country=SE', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] searchParams: URLSearchParams { 'country' => 'SE' }, 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] hash: '' 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] }, 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] data: undefined 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] }, ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] _header: 'GET /api/v2/institutions/?country=SE HTTP/1.1\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Accept: application/json\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Content-Type: application/json\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'User-Agent: Nordigen-Node-v2\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Accept-Encoding: gzip, compress, deflate, br\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Host: ob.gocardless.com\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Connection: close\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] '\r\n', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] _keepAliveTimeout: 0, 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] _onPendingData: [Function: nop], ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] responseUrl: 'https://ob.gocardless.com/api/v2/institutions/?country=SE', ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] response: { 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] status: 401, 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] statusText: 'Unauthorized', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] headers: T [AxiosHeaders] { 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] date: 'Mon, 13 Nov 2023 16:30:19 GMT', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'content-type': 'application/json', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'content-length': '110', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] connection: 'close', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] server: 'nginx', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'www-authenticate': 'Bearer realm="api"', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] vary: 'Accept, Accept-Language, Cookie', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] allow: 'GET, HEAD, OPTIONS', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'x-frame-options': 'DENY', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'content-language': 'en', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'x-content-type-options': 'nosniff', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'referrer-policy': 'same-origin' 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] }, ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] request: <ref *1> ClientRequest { ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] socket: [TLSSocket], 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] _header: 'GET /api/v2/institutions/?country=SE HTTP/1.1\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Accept: application/json\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Content-Type: application/json\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'User-Agent: Nordigen-Node-v2\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Accept-Encoding: gzip, compress, deflate, br\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Host: ob.gocardless.com\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] 'Connection: close\r\n' + 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] '\r\n', ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] path: '/api/v2/institutions/?country=SE', ... 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] }, 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] data: { 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] summary: 'Authentication failed', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] detail: 'Authentication credentials were not provided.', 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] status_code: 401 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] } 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info] } 2023-11-13T16:30:19Z app[9080ee76c53787] arn [info]} ``` ### Where are you hosting Actual? Fly.io ### What browsers are you seeing the problem on? Chrome, Safari ### Operating System Mac OSX
GiteaMirror added the bank syncregressionserverbug labels 2026-04-30 11:42:48 -05:00
Author
Owner

@MatissJanis commented on GitHub (Nov 13, 2023):

👋 Thanks for the investigation.

Have you reached out to Gocardless/Nordigen about this? Judging from all the information you've provided (and also other folks also reporting Gocardless broken) - I think the issue is on their end.

<!-- gh-comment-id:1808806572 --> @MatissJanis commented on GitHub (Nov 13, 2023): 👋 Thanks for the investigation. Have you reached out to Gocardless/Nordigen about this? Judging from all the information you've provided (and also other folks also reporting Gocardless broken) - I think the issue is on their end.
Author
Owner

@toebbel commented on GitHub (Nov 13, 2023):

Hi @MatissJanis
I haven't been in touch with them; but my first guess was also that the issue lies with GoCardless.

I tried to call https://bankaccountdata.gocardless.com/api/v2/token/new/ manually with the secredId and secredKey and I do receive an access & refresh token. So it seems like the API works without any issue. I can then use the retrieved access token to call a GET on https://ob.gocardless.com/api/v2/institutions and receive a 200.

It seems like everything works fine with the API itself.

<!-- gh-comment-id:1809067986 --> @toebbel commented on GitHub (Nov 13, 2023): Hi @MatissJanis I haven't been in touch with them; but my first guess was also that the issue lies with GoCardless. I tried to call `https://bankaccountdata.gocardless.com/api/v2/token/new/` manually with the `secredId` and `secredKey` and I do receive an access & refresh token. So it seems like the API works without any issue. I can then use the retrieved access token to call a GET on `https://ob.gocardless.com/api/v2/institutions` and receive a 200. It seems like everything works fine with the API itself.
Author
Owner

@MatissJanis commented on GitHub (Nov 13, 2023):

I just spot-checked v23.10.0, v23.11.0 and edge versions of actual-server. All of them report this issue with GoCardless (for me).

Given that the same releases were working completely fine just a couple of days ago - I find it very hard to believe this to be an issue in Actual.

So my recommendation here is to reach out to GoCardless.

<!-- gh-comment-id:1809075019 --> @MatissJanis commented on GitHub (Nov 13, 2023): I just spot-checked v23.10.0, v23.11.0 and `edge` versions of actual-server. All of them report this issue with GoCardless (for me). Given that the same releases were working completely fine just a couple of days ago - I find it very hard to believe this to be an issue in Actual. So my recommendation here is to reach out to GoCardless.
Author
Owner

@toebbel commented on GitHub (Nov 13, 2023):

Mhh. Yes. That sounds definitely like a Nordigen Issue. I can reach out to them.

<!-- gh-comment-id:1809082517 --> @toebbel commented on GitHub (Nov 13, 2023): Mhh. Yes. That sounds definitely like a Nordigen Issue. I can reach out to them.
Author
Owner

@toebbel commented on GitHub (Nov 15, 2023):

@MatissJanis I have heard back from them and it seems to be no issue with the Nordigen-node module.
I have sent them this code snippet

import * as nordigenNode from 'nordigen-node';
const GoCardlessClient = nordigenNode.default;

async function test() {
  const client = new GoCardlessClient({
    secretId: "<redacted>",
    secretKey: "<redacted>",
  });
  const response = await client.institution.getInstitutions({ country: "se" })
  console.log(response)
}

test().then(() => console.log("done"))

which initially yielded the same results as my actual-server instance on fly. The support pointed out that I was missing a call to client.generateToken(); which solved the issue for me.

I see that generateToken is called here, which in turn sets this.headers['Authorization'] in nordigen-node and that should be used when sending requests.

I did add log lines in setToken here to verify that we create a token (also added a call to setToken from institutions here)

I am not sure why the HTTP response say that authorisation headers are missing 🤔. Not sure how to proceed here.

I am pasting the support's response for reference:

Hello Tobi!

Thank you for getting back to us!

The 401 error you are receiving is caused by the access tokens expiring.

Access token expires after 24 hours and needs to be refreshed manually by making POST request to https://ob.gocardless.com/api/v2/token/refresh/ and updating it in users table. After refresh token expires, user should generate a new token using following endpoint https://ob.gocardless.com/api/v2/token/new/

According to this to restore application functionality the refresh token call needs to be made and the issue should be resolved.

Awaiting your reply.

According to the logs, actual-server generates new access tokens all the time. I don't think expiration is an issue here.

<!-- gh-comment-id:1813098909 --> @toebbel commented on GitHub (Nov 15, 2023): @MatissJanis I have heard back from them and it seems to be no issue with the `Nordigen-node` module. I have sent them this code snippet ``` import * as nordigenNode from 'nordigen-node'; const GoCardlessClient = nordigenNode.default; async function test() { const client = new GoCardlessClient({ secretId: "<redacted>", secretKey: "<redacted>", }); const response = await client.institution.getInstitutions({ country: "se" }) console.log(response) } test().then(() => console.log("done")) ``` which initially yielded the same results as my `actual-server` instance on `fly`. The support pointed out that I was missing a call to `client.generateToken()`; which solved the issue for me. I see that `generateToken` is called [here](https://github.com/actualbudget/actual-server/blob/master/src/app-gocardless/services/gocardless-service.js#L65), which in turn sets `this.headers['Authorization']` [in nordigen-node](https://github.com/nordigen/nordigen-node/blob/master/lib/index.js#L108C34-L108C34) and that should be used when sending [requests](https://github.com/nordigen/nordigen-node/blob/master/lib/index.js#L84). I did add log lines in `setToken` [here](https://github.com/actualbudget/actual-server/blob/master/src/app-gocardless/services/gocardless-service.js#L79) to verify that we create a token (also added a call to `setToken` from `institutions` [here](https://github.com/actualbudget/actual-server/blob/master/src/app-gocardless/services/gocardless-service.js#L141)) I am not sure why the HTTP response say that authorisation headers are missing 🤔. Not sure how to proceed here. I am pasting the support's response for reference: > Hello Tobi! > > Thank you for getting back to us! > > The 401 error you are receiving is caused by the access tokens expiring. > > Access token expires after 24 hours and needs to be refreshed manually by making POST request to https://ob.gocardless.com/api/v2/token/refresh/ and updating it in users table. After refresh token expires, user should generate a new token using following endpoint https://ob.gocardless.com/api/v2/token/new/ > > According to this to restore application functionality the refresh token call needs to be made and the issue should be resolved. > > Awaiting your reply. > According to the logs, actual-server generates new access tokens all the time. I don't think expiration is an issue here.
Author
Owner

@MatissJanis commented on GitHub (Nov 15, 2023):

I love how in-sync we are :)

I looked more into it and it is in fact an issue on our end. Though I find it strange how I was able to reproduce it on older Actual releases.. where it should not have been reproducible...

Anyways, the fix: https://github.com/actualbudget/actual-server/pull/278

<!-- gh-comment-id:1813102362 --> @MatissJanis commented on GitHub (Nov 15, 2023): I love how in-sync we are :) I looked more into it and it is in fact an issue on our end. Though I find it strange how I was able to reproduce it on older Actual releases.. where it should not have been reproducible... Anyways, the fix: https://github.com/actualbudget/actual-server/pull/278
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#49851