Skip to main content
Contributor I
April 30, 2025
Solved

Klaviyo Oauth Endpoint Not Working

I was previously using these URLs for OAuth which have since been deprecated https://developers.klaviyo.com/en/docs/set_up_oauth
 

Authorization URL: 'https://www.klaviyo.com/oauth/authorize'

Token URL: 'https://www.klaviyo.com/oauth/token’


I attempted to update to these URLs
 

Authorization URL: 'https://a.klaviyo.com/oauth/authorize'

Token URL: 'https://a.klaviyo.com/oauth/token'


However, the Authorization URL does not work for me. Whenever I hit the new URL(https://a.klaviyo.com/oauth/authorize) with the same parameters used with the previous authorization url(https://www.klaviyo.com/oauth/authorize) I am redirected to a blank page and nothing happens.

I now have a split solution where I am using the following and everything is functioning: 

 

Authorization URL: 'https://www.klaviyo.com/oauth/authorize'

Token URL: 'https://a.klaviyo.com/oauth/token'

Is there a known bug with the new Authorization URL(https://a.klaviyo.com/oauth/authorize)? I am unable to kick of the OAuth flow using it.

    whereisjad
    Expert Problem Solver IV
    April 30, 2025

    hopefully code below helps you.  It allows you to perform the OAuth handshake using a Python app you can run locally using Flask library (you will need to enter the CLIENT_ID and CLIENT_SECRET values for your OAuth app created in Klaviyo):

    from flask import Flask, request, redirect

    app = Flask(__name__)



    import urllib.parse

    import requests

    import base64



    # use  https://tonyxu-io.github.io/pkce-generator/ to generate these

    CODE_CHALLENGE = "”

    CODE_VERIFIER = ""



    REDIRECT_URI = "http://localhost:5001/callback"

    BASE_URL = "http://klaviyo.com"

    ASYNC_BASE_URL = "https://a.klaviyo.com"



    CLIENT_ID = ""

    CLIENT_SECRET = ""


    # feel free to modify as suitable
    SCOPES = "accounts:read accounts:write campaigns:read campaigns:write catalogs:read catalogs:write data-privacy:read data-privacy:write events:read events:write flows:read flows:write images:read images:write lists:read lists:write metrics:read metrics:write profiles:read profiles:write segments:read segments:write subscriptions:read subscriptions:write tags:read tags:write templates:read templates:write webhooks:read webhooks:write list-and-segments:read list-and-segments:write push-tokens:read push-tokens:write coupons:read coupons:write coupon-codes:read coupon-codes:write conversations:read conversations:write reviews:read reviews:write forms:read forms:write"



    ENCODED_CLIENT_INFO = base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode()).decode()



    @app.get("/")

    def read_root():

    params = dict(

    client_id=CLIENT_ID,

    response_type="code",

    redirect_uri=REDIRECT_URI,

    scope=SCOPES,

    state="NONCE",

    code_challenge_method="S256",

    code_challenge=CODE_CHALLENGE,

    )

    encoded_params = urllib.parse.urlencode(params)

    return redirect(f"{BASE_URL}/oauth/authorize?{encoded_params}")



    @app.route('/callback', methods=['GET'])

    def callback():

    code = request.args.get('code')

    print(code)

    response = requests.post(

    f"{ASYNC_BASE_URL}/oauth/token",

    headers={

    "Authorization": f"Basic {ENCODED_CLIENT_INFO}",

    "Content-Type": "application/x-www-form-urlencoded",

    },

    data=dict(

    grant_type="authorization_code",

    code=code,

    code_verifier=CODE_VERIFIER,

    redirect_uri=REDIRECT_URI,

    ),

    )

    print(response.request.headers, response.request.body)

    return response.json()



    if __name__ == "__main__":

    app.run(port=5001)

    When you run this app.  It calls Klaviyo and tries to perform the OAuth.  Once successful it will return a JSON with the access token and refresh token as described in:

    https://developers.klaviyo.com/en/docs/set_up_oauth#use-the-received-access-token

     

    — Jad A | Klaviyo + Shopify + API Integrations Specialist • 7+ Years' Experience Helping with new setups, seamless integrations, and API connections—happy to connect. http://ja-technical-consulting.xyz/

    1 reply

    whereisjad
    Expert Problem Solver IV
    Expert Problem Solver IV
    April 30, 2025

    hopefully code below helps you.  It allows you to perform the OAuth handshake using a Python app you can run locally using Flask library (you will need to enter the CLIENT_ID and CLIENT_SECRET values for your OAuth app created in Klaviyo):

    from flask import Flask, request, redirect

    app = Flask(__name__)



    import urllib.parse

    import requests

    import base64



    # use  https://tonyxu-io.github.io/pkce-generator/ to generate these

    CODE_CHALLENGE = "”

    CODE_VERIFIER = ""



    REDIRECT_URI = "http://localhost:5001/callback"

    BASE_URL = "http://klaviyo.com"

    ASYNC_BASE_URL = "https://a.klaviyo.com"



    CLIENT_ID = ""

    CLIENT_SECRET = ""


    # feel free to modify as suitable
    SCOPES = "accounts:read accounts:write campaigns:read campaigns:write catalogs:read catalogs:write data-privacy:read data-privacy:write events:read events:write flows:read flows:write images:read images:write lists:read lists:write metrics:read metrics:write profiles:read profiles:write segments:read segments:write subscriptions:read subscriptions:write tags:read tags:write templates:read templates:write webhooks:read webhooks:write list-and-segments:read list-and-segments:write push-tokens:read push-tokens:write coupons:read coupons:write coupon-codes:read coupon-codes:write conversations:read conversations:write reviews:read reviews:write forms:read forms:write"



    ENCODED_CLIENT_INFO = base64.b64encode(f"{CLIENT_ID}:{CLIENT_SECRET}".encode()).decode()



    @app.get("/")

    def read_root():

    params = dict(

    client_id=CLIENT_ID,

    response_type="code",

    redirect_uri=REDIRECT_URI,

    scope=SCOPES,

    state="NONCE",

    code_challenge_method="S256",

    code_challenge=CODE_CHALLENGE,

    )

    encoded_params = urllib.parse.urlencode(params)

    return redirect(f"{BASE_URL}/oauth/authorize?{encoded_params}")



    @app.route('/callback', methods=['GET'])

    def callback():

    code = request.args.get('code')

    print(code)

    response = requests.post(

    f"{ASYNC_BASE_URL}/oauth/token",

    headers={

    "Authorization": f"Basic {ENCODED_CLIENT_INFO}",

    "Content-Type": "application/x-www-form-urlencoded",

    },

    data=dict(

    grant_type="authorization_code",

    code=code,

    code_verifier=CODE_VERIFIER,

    redirect_uri=REDIRECT_URI,

    ),

    )

    print(response.request.headers, response.request.body)

    return response.json()



    if __name__ == "__main__":

    app.run(port=5001)

    When you run this app.  It calls Klaviyo and tries to perform the OAuth.  Once successful it will return a JSON with the access token and refresh token as described in:

    https://developers.klaviyo.com/en/docs/set_up_oauth#use-the-received-access-token

     

    — Jad A | Klaviyo + Shopify + API Integrations Specialist • 7+ Years' Experience Helping with new setups, seamless integrations, and API connections—happy to connect. http://ja-technical-consulting.xyz/