Refresh token was not valid

I'm using the example PHP code as a starting point. Trying to refresh the access token always gives me an error.

{"error":"invalid_grant","error_description":"The refresh token was not valid."}.

I'm sending the following body:

Array ( [grant_type] => refresh_token [refresh_token] => xxxxxxxxxxxxx )

With the following headers:

Array ( [0] => Content-type: application/x-www-form-urlencoded [1] => Authorization: Basic XXXXXXXXX

I know the refresh token is valid because it's returned from the API. I tried to refresh the access token immediately and also after an hour but get the same error, for some reason.

Any ideas?

Comments

  • Michael Tims
    Michael Tims Blackbaud Employee
    Sixth Anniversary Kudos 2 Name Dropper Participant

    @James Benson - it's difficult to tell with the information I am seeing… A common mistake that we often see regarding refresh tokens is when you attempt to use the same refresh token to refresh multiple access tokens. Each time you refresh an access token you will be returned a new refresh token and the previous refresh token is invalidated. Can you confirm if you are using the newly-generated refresh token each time and not attempting to reuse a refresh token more than once?

    See the Common auth issues page for more details.

    Thanks!

  • Alex Wong
    Alex Wong Community All-Star
    Ninth Anniversary Kudos 5 Facilitator 3 bbcon 2025 Attendee Badge

    @James Benson
    I used to do refresh token so here's what I have:

    ff9e860a87f4910acf267f1fffe5d39b-huge-im

    I store my client_id, client_secret, token and refresh_token in SharePoint List, every 59 minutes (60 minutes is when a token expires), I have an automation that runs the above action, which “refresh” the token for another 60 minutes. Once the above ran, I get back a new token and a new refresh token, which I store/overwrite the token and refresh token in SharePoint List.

  • Alex Wong
    Alex Wong Community All-Star
    Ninth Anniversary Kudos 5 Facilitator 3 bbcon 2025 Attendee Badge

    @James Benson
    Looking at your request, looks like you are not hitting the endpoint properly.

    You need to have body for:
    grant_type=refresh_token
    refresh_token=xxxxxxxxxxxxx (your valid refresh token)
    client_id=xxxxxxxxxx
    client_secret=xxxxxxxxx

    Your header just need to have Content-Type=x-www-form-urlencoded, no need for Authorization.

  • @Alex Wong
    Thanks I will check that out. I think the client ID and secret are passed in the auth header.


    I'm guessing it might be something to do with how I'm storing the refresh token and it's not being saved properly.

  • @Alex Wong
    Resolved this now.

    It was indeed how I was storing the refresh token. I'm using wordpress and it was adding the values but not updating them.

  • Alex Wong
    Alex Wong Community All-Star
    Ninth Anniversary Kudos 5 Facilitator 3 bbcon 2025 Attendee Badge

    @James Benson
    For calling the refresh token endpoint, you can pass the client_id and client_secret (along with refresh_token and grant_type) in the body of the HTTP call. You can also do Authorization it seems, but I do call using client_id and client_secret as you saw in my screenshot in previous post.

    b22a5ce964c111a76c0e6bc11fa73b6b-huge-im