SSO

Login via SSO (Single Sign-On)

The SSO process enables seamless login of advertisers to the Adshero panel directly from the shop’s platform, without the need to provide separate login credentials.

Before SSO is used, the seller/advertiser mapping must already exist in Adshero for the whitelabel. The sellerId passed to SSO is the seller identifier from the feed (g:external_seller_id or ah:external_seller_id) and must be assigned to a SELLER advertiser in that whitelabel. SSO does not create seller/advertiser mappings.

JWT Token

The JWT token must be signed using the HMAC-SHA256 (HS256) algorithm with a shared secret. The signing secret is provided by the Adshero team as a base64-encoded value.

Before signing the token, decode the secret from base64 and use the decoded bytes as the HS256 HMAC key. Do not use the raw secret string bytes as the key.

Header:

{
  "alg": "HS256"
}

Payload — should contain the following fields:

{
  "sub": "user@example.com",
  "iss": "string",
  "seller_ids": ["SELLER-001"],
  "exp": 1893456000
}

Token field descriptions:

  • sub — User’s email address. This will also be the login of the user created in the Adshero system.
  • iss — Unique whitelabel identifier (UUID) assigned by Adshero.
  • seller_ids — List of seller identifiers (external_seller_id from the feed) that the user has access to. It must contain the value passed in the sellerId query parameter; otherwise login is rejected.
  • exp — Token expiration time as a Unix timestamp in seconds, not milliseconds. A token with an expired exp value will be rejected.
ℹ️
The Adshero panel displays the first and last name of the logged-in user. Since the JWT token does not contain this data, during the user creation process, the part of the email address before the @ sign is used as the first name. The last name remains empty.

Example SSO URL generator

The following Python script can be used for testing or as an implementation reference. It decodes the base64 secret, signs the JWT with HS256, adds the selected seller to seller_ids, sets exp to one hour from execution time, and prints a ready-to-use SSO login URL.

#!/usr/bin/env python3
import base64
import hashlib
import hmac
import json
import sys
import time
import urllib.parse


iss, secret, seller = sys.argv[1:4]
sub = sys.argv[4] if len(sys.argv) > 4 else "test@adshero.io"


def b64(value):
    return base64.urlsafe_b64encode(value).rstrip(b"=").decode()


header = {"alg": "HS256", "typ": "JWT"}
payload = {"sub": sub, "iss": iss, "seller_ids": [seller], "exp": int(time.time()) + 3600}

unsigned = b64(json.dumps(header, separators=(",", ":")).encode())
unsigned += "." + b64(json.dumps(payload, separators=(",", ":")).encode())
sig = b64(hmac.new(base64.b64decode(secret), unsigned.encode(), hashlib.sha256).digest())
token = unsigned + "." + sig

print("https://api.adshero.io/v1/auth/sso?token=" + urllib.parse.quote(token) + "&sellerId=" + urllib.parse.quote(seller))

Usage:

python3 sso.py '<iss>' '<base64-secret>' '<seller-id>' '<email>'

Argument descriptions:

  • iss - whitelabel identifier assigned by Adshero.
  • base64-secret - base64 signing secret received from Adshero.
  • seller-id - seller identifier from the feed, passed as sellerId and included in seller_ids.
  • email - user’s email address stored in the sub field.

The script prints a complete URL in the following format:

https://api.adshero.io/v1/auth/sso?token=...&sellerId=...

Open the printed URL in a browser to start the SSO login flow for the selected seller.

Authentication endpoint

The JWT token generated by the shop is sent to Adshero at the following endpoint:

GET https://api.adshero.io/v1/auth/sso?token={tokenJWT}&sellerId={sellerId} HTTP/2
curl --location --request GET \
    'https://api.adshero.io/v1/auth/sso?token={tokenJWT}&sellerId={sellerId}'

Query parameter descriptions:

  • token — JWT token in standard format (header.payload.signature).
  • sellerId — ID of the currently selected seller (external_seller_id from the feed).

Response behavior:

  • Success — HTTP 302 with the Location header set to a generated magic-link login flow for the whitelabel frontend domain.
  • Error — HTTP 302 with Location: /v1/auth/sso/error. This applies to an invalid token, missing seller/advertiser mapping, bad seller (including sellerId missing from seller_ids), expired token or bad signature. The endpoint does not return a JSON error response.