Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refreshToken returns 401 #697

Closed
LauraImpact opened this issue Jul 26, 2024 · 3 comments
Closed

refreshToken returns 401 #697

LauraImpact opened this issue Jul 26, 2024 · 3 comments

Comments

@LauraImpact
Copy link

SDK you're using (please complete the following information):

  • Version ^9.0.0

Describe the bug
When a user has an existing token set and the access_token has expired, attempts to refresh the token are failing.

To Reproduce

  • Fetch existing token set from database
  • Check if access_token is expired
  • If true, try to refresh the token
  • API request returns 401
const xero = createXeroClient();

    /** check for existing tokenSet in db (xero will return existing tokenSet if org is already connected) */
    let existingTokenSet = await getXeroTokenSet(userId, clientUser.client_id);
    console.log("existing tokens returned");
    /** if tokenSet already exists, check if its expired */
    if (existingTokenSet) {
      console.log("if statement exec");
      /** Token needs to be set in the xero client, even if it's expired - required for xero.refreshToken func */
      await xero.setTokenSet(existingTokenSet);
      await xero.initialize();

      xero.updateTenants(false);
      console.log("update tenants called");

      console.log("token from database", existingTokenSet.refresh_token);
      console.log(
        "check db token expired",
        isXeroTokenExpired(
          existingTokenSet.created_at,
          existingTokenSet.expires_in
        )
      );

      const expired = isXeroTokenExpired(
        existingTokenSet.created_at,
        existingTokenSet.expires_in
      );

      if (expired) {
        console.log("read tokens expired");

        existingTokenSet = await handleXeroTokenRefresh({
          xeroClient: xero,
          refreshToken: existingTokenSet.refresh_token,
          userId,
          clientId: clientUser.client_id,
        });


        console.log("refreshed token returned");

        await xero.setTokenSet(existingTokenSet);
        await xero.updateTenants(false);
      }
export const handleXeroTokenRefresh = async ({
refreshToken,
userId,
clientId,
xeroClient,
}: {
refreshToken: string;
userId: string;
clientId: number;
xeroClient: XeroClient;
}) => {
try {
  const refreshTokenSet = await xeroClient.refreshToken().catch((error) => {
    console.error("Error refreshing xero token");
    throw error;
  });

  console.log("Token set received:", refreshTokenSet);

  const validationResult = createXeroTokenSchema.safeParse({
    ...refreshTokenSet,
    expires_in: refreshTokenSet.expires_in,
    user_id: userId,
    client_id: clientId,
  });

  if (!validationResult.success) {
    console.error("Validation error:", validationResult.error);
    throw new Error("Error validating xero token set");
  }

  await deleteXeroToken({ userId, refreshToken, clientId });

  const newTokenSet = await createXeroTokenEntry(validationResult.data);
  console.log("Refreshed token set successfully");
  return newTokenSet;
} catch (error) {
  console.error("Error refreshing xero tokens: ", error);
  throw error;
}
};

Receiving this error in the logs:

outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      strictContentLength: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: [TLSSocket],
      _header: 'GET /connections HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFDQUY4RTY2NzcyRDZEQzAyOEQ2NzI2RkQwMjYxNTgxNTcwRUZDMTkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJISy1PWm5jdGJjQW8xbkp2MENZVmdWY09fQmsifQ.eyJuYmYiOjE3MjE3MDc0NjQsImV4cCI6MTcyMTcwOTI2NCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS54ZXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vaWRlbnRpdHkueGVyby5jb20vcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiQUIxQ0FDQkI3REMwNDYyOTk3MTFBMTBGREEwQ0E4RDAiLCJzdWIiOiIwODNlYzE0ZGIwMjM1NTMxODc0MmFkOGI5YWI1OTEzMyIsImF1dGhfdGltZSI6MTcyMTcwNzQ0OCwieGVyb191c2VyaWQiOiI2NmQ5NTlkNC02NzQ0LTQ1ZGQtOTRjOS01NmJhNmM3ODc4ZjciLCJnbG9iYWxfc2Vzc2lvbl9pZCI6ImQwMmRmNjYyMTk3OTRkYTZhNTE5NzBlMjU3MmVkZDIzIiwic2lkIjoiZDAyZGY2NjIxOTc5NGRhNmE1MTk3MGUyNTcyZWRkMjMiLCJqdGkiOiIwN0ExNjU3MDZCRDczQjYzOUFBQTY2M0I2NDNDNTkxRSIsImF1dGhlbnRpY2F0aW9uX2V2ZW50X2lkIjoiOWZiNGJlZGEtZmFlNy00YzQxLTg0NDktOTYwMmE5ZTI5YzQwIiwic2NvcGUiOlsiZW1haWwiLCJwcm9maWxlIiwib3BlbmlkIiwiYWNjb3VudGluZy5zZXR0aW5ncyIsImFjY291bnRpbmcudHJhbnNhY3Rpb25zIiwiYWNjb3VudGluZy5jb250YWN0cyIsIm9mZmxpbmVfYWNjZXNzIl0sImFtciI6WyJwd2QiXX0.DGZqPJJEDCpwys6oN4P5jiVn_tftY1e86wFOUUz1iA0tAn-YrBnQQIxNu_i2AKmpA6dc_DsTBJdgnQ4dUxVMzKMMWEvnAw2c08kbocV4i8Of8h4iJ1Xg5JCQ8TlsGNSw6RsyFWx5Dl7i6ktbq6hqO23CdzAuTJeeAnw7zuQwSrQucYnY1g99PjZb8y-iuB1uuniqGLEixpVWHEgezKnyyEiOs5dAxKSa4S-LwytmPVvKTFobhiPU84A6joa9H7jFIQpn_hhJic5RrJAJ3GZKSYYQ_7mhteuBxgBBriyGZETel4dJYrv2CWNA13swaprKYgrukPZqzzGeUaeGnaDYtw\r\n' +
        'User-Agent: axios/1.7.2\r\n' +
        'Accept-Encoding: gzip, compress, deflate, br\r\n' +
        'sentry-trace: 0347fa069ac24d93b8917fe33e4ded1c-b81bcb29bbbe68f2-0\r\n' +
        'baggage: sentry-environment=production,sentry-release=8c0a8d397c87185f2e8f481e427b30f86ff58992,sentry-public_key=7eb42c47637793b35e511de17cd63f43,sentry-trace_id=0347fa069ac24d93b8917fe33e4ded1c\r\n' +
        'x-vercel-id: syd1::r6p5k-1721967047281-c1800b0bf8bd\r\n' +
        'Host: api.xero.com\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      joinDuplicateHeaders: undefined,
      path: '/connections',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'api.xero.com',
      protocol: 'https:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(errored)]: null,
      [Symbol(kHighWaterMark)]: 16384,
      [Symbol(kRejectNonStandardBodyWrites)]: false,
      [Symbol(kUniqueHeaders)]: null
    },
    data: {
      Type: null,
      Title: 'Unauthorized',
      Status: 401,
      Detail: 'TokenExpired: token expired at 07/23/2024 04:34:24',
      Instance: '7c4e4c62-e326-4e35-9f33-40c387542c5a',
      Extensions: {}
    }
  }
}

Expected behavior
Expected the token to be refreshed and a new token set returned.

Copy link

PETOSS-485

Copy link

Thanks for raising an issue, a ticket has been created to track your request

@LauraImpact
Copy link
Author

Resolved the issue, so closing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant