Access token expired in V3

AprilD761
Rookie
0 Votes

I am looking to upgrade constant contact api to V3 api. For making api calls I need the access token. I generated access token using OAuth2.0 Client Flow. And tested  api call get contacts. Its is working. After few times I call the api but gives the error unauthorized access token. It was because of the access token get expired. In OAuth2.0 Client Flow it is saying that the life span of access token in some hours.

 

So how I use this for long term use. That is I have to generate new access token time to time and it is not practical.

Currently I am using the api to retrieve/add/update contacts to constant contact account. In constant contact  api I don't face this type of issue, because there access token is not expired.

9 REPLIES 9
Jimmy_D
Employee
0 Votes

Hello @AprilD761 ,

 

Thank you for reaching out to Constant Contact's API Support.

 

If you continue going through the oAuth documentation for v3 you will notice that it mentions a Refresh Token section after the Access Token section. You use the Refresh Token to get a new Access Token. You can find this documentation here


Regards,
Jimmy D.
Tier II API Support Engineer
AprilD761
Rookie
0 Votes

Yes, I tried the OAuth2.0 Server Flow also.

As you mentioned, we use the Refresh Token to get a new Access Token. This will also expire. In step 4, we can generate Access Token and a Refresh Token using Authorization Code. And when the Access Token expired using the Refresh Token we can regenerate new Access Token and refresh token.

 

That is time to time Access Token get expired and using the refresh token we generate new access token.

 

So time to time I have to change the code. Right?

David_B.
Employee
0 Votes

Hello,

 

Refresh Tokens do not expire the way that Access Tokens do.

 

When using the Server flow, you are given a Refresh Token as well as an Access Token. When your Access Token has expired, you can exchange the Refresh Token for a new Access Token as well as a new Refresh Token. You would then continue doing this with the new Refresh Tokens obtained.


Regards,
David B.
Tier II API Support Engineer

 

 

AprilD761
Rookie
0 Votes

Hi, 

As you said

Refresh Tokens do not expire the way that Access Tokens do.

 

I got:  string(92) "{"error_description":"unknown, invalid, or expired refresh token","error":"invalid_grant"} "

 

My code is: 

function refreshToken($refreshToken, $clientId, $clientSecret) {
    $ch = curl_init();
    $base = 'https://idfed.constantcontact.com/as/token.oauth2';
    $url = $base . '?refresh_token=' . $refreshToken . '&grant_type=refresh_token';
    curl_setopt($ch, CURLOPT_URL, $url);
    $auth = $clientId . ':' . $clientSecret;
    $credentials = base64_encode($auth);
    $authorization = 'Authorization: Basic ' . $credentials;
    curl_setopt($ch, CURLOPT_HTTPHEADER, array($authorization));

    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}
$refreshToken = "xxxxxx";
$clientId="xxxxxxxx";
$clientSecret="xxxxxxxx";

var_dump(refreshToken($refreshToken,  $clientId, $clientSecret));
Jimmy_D
Employee
0 Votes

Hi @AprilD761,

 

Your code looks correct. You would get an error if somehow the $refreshToken was accidentally pulling in the Access Token instead of the previous Refresh Token. Since we cannot see the rest of the code I would ensure it is pulling in the correct value.


Regards,
Jimmy D.
Tier II API Support Engineer
LauraV545
Campaign Contributor
0 Votes

If the access token is expired, will it return 401 The Access Token used is invalid, and after detecting that has happened, that is when to use the Refresh token to ask for another Access Token? Or is it recommended to periodically request a new access token to keep the Access Token from expiring?

FadyY8
Campaign Collaborator

I am not entirely sure what does CTCT thinks.

If any other developers out there need the code here it is for MVC C#


[Route("check_session_api")]
        public object CheckSessionAPI()
        {
            if (Session["ResponseAPI"] == null)
            {
                return "No result";
            }
            else
            {
                return Session["ResponseAPI"].ToString();
            }
        }


        [Route("api_request")]
        public ActionResult ApiRequest()
        {
            var url = "https://api.cc.email/v3/idfed" + "?client_id=" + apiKey + 
                "&redirect_uri=" + redirectURL + 
                "&scope=contact_data+campaign_data" + "&response_type=code";
            return RedirectPermanent(url);
        }

        [Route("api_response")]
        public object ApiResponse()
        {
            try
            {
                string code = Request.QueryString["code"];
                if (code != null)
                {
                    using (var webClient = new WebClient())
                    {
                        byte[] bytes = Encoding.UTF8.GetBytes(apiKey + ":" + client_secret);
                        var base64 = Convert.ToBase64String(bytes);

                        var client = new RestClient(tokenURL);
                        var request = new RestRequest(Method.POST);
                        request.AddHeader("Authorization", "Basic " + base64);
                        request.AddParameter("code", code);
                        request.AddParameter("redirect_uri", redirectURL);
                        request.AddParameter("grant_type", "authorization_code");

                        IRestResponse res = client.Execute(request);

                        if (res.StatusCode.ToString().ToLower().IndexOf("bad") < 0)
                        {
                            Session["ResponseAPI"] = res.Content;
                        }
                    }
                    return RedirectToAction("Index", "Home");
                }
                return null;
            }
            catch (Exception ex)
            {
                return ex;
            }
        }


        [Route("api_refresh")]
        public object ApiRefresh(string refresh_token)
        {
            try
            {
                using (var webClient = new WebClient())
                {
                    var client = new RestClient(tokenURL);
                    var request = new RestRequest(Method.POST);
                    request.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(apiKey + ":" + client_secret)));
                    request.AddParameter("refresh_token", refresh_token);
                    request.AddParameter("grant_type", "refresh_token");
                    IRestResponse res = client.Execute(request);

                    if (res.StatusCode.ToString().ToLower().IndexOf("bad") < 0)
                    {
                        ///success
                        Session["ResponseAPI"] = res.Content;                        
                    } else
                    {
                        //failure                         
                        refresh_token = "{hard code the refresh token}";
                        return ApiRefresh(refresh_token);
                    }
                    return Session["ResponseAPI"];                    
                }
            }
            catch (Exception ex)
            {
                return ex;
            }
        }

 Now the major PROBLEM with this design are:

1) You must hard code the refresh token and good luck with that !!!!

2) You must be logged in into https://developer.constantcontact.com for this whole thing to even work!! That's right. So if you are a developer like me and write this code for a website to collect subscriber emails you are screwed (no other way to put that).

 

Constant Contact Team, You need to fix this and asap otherwise I will be happy to take it away from you to mailchimp.

UGH!!!

igvinc
Constant Contact Partner
0 Votes
I believe you are correct and I can confirm that I too have spent countless hours on this same issue.

summary of problem: The refresh token expires. making it impossible to hard code anything into an application that will allow us to collect emails from a simple custom-built form using PHP.

We have a simple newsletter on our website that uses version 2 of the API.

every attempt I have made to use version 3 has failed... I took another stab at it today and I ended up in the same loop that you have ended up in.

The refresh token continually expires every time I try to use it.

ERGO: it is a never-ending paradox that is unsolvable.

My conclusion was that I'll just stick with version 2. (or suggest clients use another newsletter platform)

I've thought about making a video showing the problem...

I think a good way to approach this is simply asking this question:

is it possible for us to build a simple PHP form that has hard-coded our API key, API secret and 1 unchanging refresh token that will always be reliable forever collecting an email on a simple pop-up AJAX newsletter subscribe form?

My conclusion was: no this is impossible. (I would very much like to be wrong about that.)
Courtney_E
Moderator

Thank you for reaching out to Constant Contact API Developer Support. My team is here to assist outside software developers with questions about building into Constant Contact's API.

 

Access tokens automatically expire two hours after their last use, with a maximum lifetime of twenty four hours. The refresh token does not expire unless it is used or a new refresh token has been generated. Refresh tokens can only be used once, as generating a new set of tokens causes all previous tokens to expire.

 

You will need to set the access token and the refresh token as values for corresponding variables in your application, so that when your program runs through step 5 of the OAuth2.0 Server Flow to get the new set of tokens it can assign new values to those variables to maintain an authenticated connection.

 

V3 API - Refresh the Access Token

https://v3.developer.constantcontact.com/api_guide/server_flow.html#step-5-refresh-the-access-token

 

How to Make Access Tokens Last Longer

https://developer.constantcontact.com/api_guide/faqs_manage_applications.html


Regards,

Courtney E.
Tier II API Support Engineer

Did I answer your question?
If so, please mark my post as an "Accepted Solution" by clicking the Accept as Solution button in the bottom right hand corner of this post.
Resources
Developer Portal

View API documentation, code samples, get your API key.

Visit Page

Announcements

API Updates

Join our list to be notified of new features and updates to our V3 API.

Sign Up