Jump to content

Assistance Required with OAuth Token Exchange Issue


Recommended Posts

Certainly! Here's a draft of a support message you could send to Sage:

Dear Sage Support Team,

I am currently integrating the Sage API within a JavaScript web application and have encountered an issue during the OAuth token exchange process. I've implemented the Authorization Code OAuth 2.0 grant flow as per the documentation, but I'm receiving an InternalServerError with an empty message from the refresh token endpoint.

Here is a summary of my approach:

export async function GET(req: Request, res: Response) {
  const { searchParams } = new URL(req.url);
  const code = searchParams.get("code");
  const state = searchParams.get("state");
  // Ensure that the environment variables are not undefined
  const clientId = process.env.SAGE_CLIENT_ID;
  const clientSecret = process.env.SAGE_CLIENT_SECRET;
  const redirectUri = `${process.env.NEXT_PUBLIC_URL}/api/auth/callback`;

  if (!clientId || !clientSecret) {
    return new Response("Environment variables not set", { status: 500 });

  if (!code) {
    return new Response("Code not found", { status: 400 });

  if (!state) {
    return new Response("State not found", { status: 400 });

  const params = new URLSearchParams({
    client_id: clientId,
    client_secret: clientSecret,
    code: `${code}`,
    grant_type: "authorization_code",
    redirect_uri: redirectUri,
    code_verifier: state,

  const tokenResponse = await fetch("https://oauth.accounting.sage.com/token", {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    body: params,

  const tokenData = await tokenResponse.json();

  if (!tokenResponse.ok) {
    return new Response(JSON.stringify(tokenData), {
      status: tokenResponse.status,
  return new Response(JSON.stringify(tokenData), { status: 200 });
  1. Redirecting users to the /authorize endpoint for authentication.
  2. The user gets successfully redirected to the callback url after authentication.
  3. Attempting to exchange the authorization code for an access token at the /oauth/token endpoint.
  4. Using environment variables for SAGE_CLIENT_ID, SAGE_CLIENT_SECRET, and the redirect_uri.

Despite following the documented steps, the token exchange is resulting in an error, which leads to a failure in the authentication process. I have verified that the environment variables are correctly set, the state parameter is consistent to mitigate CSRF, and that the redirect URI matches the callback URL provided during the registration process.

{"error":"invalid_grant","error_description":"The submitted \"code\" has not been found."}

Could you assist me in resolving this issue? Any guidance or insight you can provide would be greatly appreciated. If required, I can provide the request IDs or timestamps for the failed requests.

Thank you for your assistance.

Kind regards, Jaedan

Link to comment
Share on other sites

Hi Jaedan,

I can't see where you are setting the grant_type to refresh_token in the code you've provided. I've included JS used in our POSTMAN collections to exchange the refresh_token for your information.

Our authentication guide is also a good reference. https://developer.sage.com/accounting/guides/authenticating/authentication/


      url:  'https://oauth.accounting.sage.com/token',
      method: 'POST',
      header: {
        'Accept': 'application/json',
        'Content-Type': 'application/x-www-form-urlencoded',
      body: {
          mode: 'urlencoded',
          urlencoded: [
            {key: "client_id", value: pm.environment.get('clientId'), disabled: false},
            {key: "client_secret", value: pm.environment.get('clientSecret'), disabled: false},
            {key: "grant_type", value: "refresh_token", disabled: false},
            {key: "refresh_token", value: pm.environment.get('refreshToken'), disabled: false}



Link to comment
Share on other sites

Hi Mark,

Thanks for the quick response.

I think we might be talking past each other. I'm still at step two, where I'm supposed to exchange the authorization code for an access token. I haven't gotten to the point of refreshing tokens because I haven't successfully received the initial access token yet. I've managed to get the authorization code after the user is redirected to the callback URL, but that's where I'm hitting a roadblock.

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in

Sign In Now

  • Create New...