---
title: "Cum expiră și cum se reînnoiesc tokenurile Shopify Admin API: tokenuri permanente, tokenuri care expiră și capcanele reînnoirii"
description: "Tokenurile Shopify Admin API sunt de mai multe feluri și nu se tratează la fel: un token permanent de aplicație custom nu trebuie să treacă niciodată prin logica de reînnoire, iar unul care expiră se reînnoiește cu un refresh token de unică folosință, pe care îl salvezi de fiecare dată. Cele mai multe pane de token pe care le-am avut nu au venit din tokenuri expirate, ci din reînnoire aplicată tokenului greșit sau din două reînnoiri care s-au călcat pe picioare."
date: 2026-10-11
lang: ro
canonical: https://goingstellar.ro/ro/metode/tokenuri-shopify-admin-api-expirare-reinnoire/
author: Going Stellar
publisher: GOING STELLAR S.R.L.
topic: Inginerie / Shopify API
license: CC BY 4.0
alternate_en: https://goingstellar.ro/methods/shopify-admin-api-tokens-expiring-refresh/
---

# Cum expiră și cum se reînnoiesc tokenurile Shopify Admin API: tokenuri permanente, tokenuri care expiră și capcanele reînnoirii

*Tokenurile Shopify Admin API sunt de mai multe feluri și nu se tratează la fel: un token permanent de aplicație custom nu trebuie să treacă niciodată prin logica de reînnoire, iar unul care expiră se reînnoiește cu un refresh token de unică folosință, pe care îl salvezi de fiecare dată. Cele mai multe pane de token pe care le-am avut nu au venit din tokenuri expirate, ci din reînnoire aplicată tokenului greșit sau din două reînnoiri care s-au călcat pe picioare.*

> Inginerie · Shopify API · 2026-10-11 · https://goingstellar.ro/ro/metode/tokenuri-shopify-admin-api-expirare-reinnoire/

## Pe scurt

- Un 401 de la Shopify înseamnă de obicei tipul greșit de token pentru acel magazin, nu un token expirat; află tipul tokenului înainte de fiecare apel.
- Un token Shopify permanent de aplicație custom nu trebuie să treacă niciodată prin reînnoirea OAuth; dă-i o expirare foarte îndepărtată dacă baza de tokenuri cere una.
- Tokenurile offline Shopify care expiră durează 1 oră, iar refresh tokenurile lor de unică folosință durează 90 de zile, deci fiecare reînnoire trebuie să salveze noul refresh token.
- Un proces care nu poate scrie în baza de date nu trebuie lăsat să reînnoiască un token Shopify, fiindcă reînnoirea consumă refresh tokenul vechi.
- Șterge un refresh token salvat doar sub un lacăt per magazin și după recitire; altfel o reînnoire paralelă care a pierdut șterge tokenul nou al celei care a câștigat.

## Ce feluri de tokenuri Shopify Admin API există

Un token de acces Shopify Admin API este valoarea pe care un program o trimite în antetul `X-Shopify-Access-Token` la fiecare cerere către Admin API. În practică întâlnim trei feluri. **Tokenul offline permanent** (fără expirare), de obicei tokenul `shpat_` al unei aplicații custom, rămâne valabil până la dezinstalarea aplicației sau rotirea secretului ei. **Tokenul offline care expiră** trăiește 1 oră și vine cu un **refresh token** (prefix `shprt_`) valabil 90 de zile, care se poate folosi o singură dată. **Tokenul emis la cerere** se obține din credențialele de client ale aplicației și trăiește cam 24 de ore, așa că nu are rost să-l stochezi.

Shopify mai emite și tokenuri online, legate de un utilizator autentificat și valabile cel mult 24 de ore; pentru lucrul în fundal nu le folosim. Toată metoda încape într-o regulă: **un token permanent nu trece niciodată prin codul de reînnoire, iar un token care expiră se reînnoiește mereu pe o singură cale, atentă, care salvează noul refresh token.**

## Pasul 1: află tipul tokenului înainte de fiecare apel

Fiecare magazin Shopify pe care îl accesăm din cod are un rând într-un registru de magazine, iar coloana de token conține fie un token static, fie un **marcaj care se descrie singur**: numește cele două credențiale din care se emite tokenul la cerere. O singură funcție citește registrul, recunoaște marcajul, emite tokenul când e nevoie și întoarce unul valid. Scripturile nu citesc niciodată registrul direct.

Șase magazine răspundeau scripturilor noastre cu `401 Invalid API key or access token`, iar reflexul a fost „a expirat tokenul, reînnoiește-l”. Nu expirase nimic. Scripturile citeau registrul direct și trimiteau textul marcajului ca și cum ar fi fost token. Am reparat funcția de rezolvare, apoi am găsit o a doua unealtă, cu propriul cititor de registru, care greșea la fel; reparația trebuie dusă în fiecare copie. Un 401 de la Shopify înseamnă de obicei *tip greșit de token pentru magazinul ăsta*, abia apoi *token mort*.

Tokenurile sunt secrete: stau doar în seif, intră în proces prin pipe și nu se afișează. Când un log trebuie să identifice unul, arată ultimele 4 caractere.

## Pasul 2: lasă tokenurile permanente în pace

Un token permanent `shpat_` de aplicație custom nu are refresh token și nici dată de expirare. Un manager scris pentru tokenuri care expiră va încerca la un moment dat să-l reînnoiască, va eșua și poate marca magazinul drept stricat. Regula noastră: un token permanent de aplicație custom nu trece niciodată prin reînnoirea OAuth, iar dacă baza de tokenuri cere o dată de expirare, primește una foarte îndepărtată, ca ramura de reînnoire să nu se poată declanșa.

Aplicațiile custom sunt scutite de obligația Shopify de a folosi tokenuri care expiră; scutirea dispare când aceeași aplicație e distribuită public.

## Pasul 3: cere și reînnoiește corect tokenurile care expiră

Shopify întoarce un token offline care expiră doar dacă cererea îl cere explicit cu `expiring=1`, atât în fluxul de token exchange, cât și în cel cu cod de autorizare. Ambele cereri sunt form-encoded, nu JSON. Fără parametru, Shopify întoarce un token care nu expiră, adică valoarea implicită documentată. Conform regulii publicate de Shopify, aplicațiile publice create începând cu 1 aprilie 2026 trebuie să folosească tokenuri offline care expiră, iar cele mai vechi trebuie să migreze până la 1 ianuarie 2027.

La una dintre aplicațiile noastre, alegerea distribuției publice a pornit verificarea pe loc: același token care întorcea 200 mai devreme a început să primească `403 Non-expiring access tokens are no longer accepted for the Admin API` la fiecare apel. În flota noastră de aplicații, 9 din 12 s-au vindecat când am șters sesiunea offline salvată și am reîncărcat aplicația, care a emis un token care expiră; celelalte 3 nu aveau un singur flag de configurare și au continuat să emită tokenuri fără expirare până l-am adăugat. Un redeploy singur nu vindecă un token fără expirare, fiindcă biblioteca îl consideră valabil pentru totdeauna și nu-l mai schimbă.

**Salvează refresh tokenul la fiecare reînnoire.** Webhook-urile și joburile programate nu au sesiune de utilizator, deci refresh tokenul e singura lor cale de acces. Fiecare reînnoire consumă refresh tokenul vechi și întoarce unul nou. Un `401` la reînnoire înseamnă că accesul e mort: te oprești și ceri cuiva să redeschidă aplicația. Un `5xx`, un `429` sau o eroare de rețea sunt trecătoare: reîncerci cu *același* refresh token, fiindcă Shopify reîntoarce același răspuns timp de 1 oră. Noi reînnoim când au mai rămas sub 10 minute de valabilitate.

Atenție: schimbul care migrează un token vechi revocă imediat tokenul vechi, chiar și la un test. Migrează dintr-un pas și salvează rezultatul.

## Capcanele reînnoirii în care am căzut

**O simulare „doar citire” a ars un refresh token.** Un script de test își forța sesiunile de bază de date pe read-only și apoi citea din Shopify prin codul de producție. Tokenul de acces mai avea 8 minute, sub marja de 10, așa că codul l-a reînnoit. Shopify a consumat refresh tokenul și a emis unul nou, iar scriptul nu l-a putut salva. L-a salvat fereastra de grație Shopify: 7 minute mai târziu, sistemul live a reînnoit cu refresh tokenul vechi și a primit același token nou. Reparația e un flag la nivel de proces care interzice complet reînnoirea; orice proces doar de citire rulează cu el, și numai procesele care scriu au voie să reînnoiască.

**Două reînnoiri simultane au șters tokenul nou.** O reînnoire a reușit și a salvat un refresh token nou. O secundă mai târziu, o a doua reînnoire, pornită în paralel cu refresh tokenul vechi, a primit 401, iar handlerul ei de eroare a șters refresh tokenul salvat, care între timp era cel nou, al câștigătoarei. După o oră a expirat tokenul de acces și magazinul a rămas fără API până când cineva a deschis aplicația din adminul magazinului. Reparația e un lacăt pe magazin: tokenul se șterge doar sub lacăt, după ce recitești magazinul și confirmi că refresh tokenul salvat e tot cel folosit de cererea eșuată.

**Un client HTTP din cache trimitea în continuare tokenul vechi.** Cache-ul nostru ținea câte un client per magazin, cu tokenul copt în antete. Comparația de tokenuri se făcea pe obiectul greșit, așa că după o rotire făcută în alt task cache-ul decidea că nu s-a schimbat nimic, iar timp de 73 de minute multe magazine au răspuns cu 401 în mijlocul duratei de viață a tokenurilor. Reparația compară tokenul din antetul clientului viu cu cel salvat, iar la un 401 reînnoiește o dată și reîncearcă o dată. Același incident a mai avut o lecție: un handler de eroare a transformat pana într-o decizie de business („comanda e ciornă, sar peste ea”), iar nouă comenzi au plecat fără un produs. O citire eșuată se loghează ca eșec, nu ca o concluzie.

## Limitele de rată și așteptarea între cereri

Admin GraphQL API folosește o găleată care se scurge (leaky bucket) per aplicație și magazin. Pe planul standard, găleata are 1000 de puncte și se reumple cu 100 de puncte pe secundă; o interogare costă implicit 1 punct, o mutație 10. Citește `extensions.cost.throttleStatus` la fiecare răspuns, încetinește când `currentlyAvailable` scade sub aproximativ 200, iar la HTTP 429 respectă `Retry-After`.

REST Asset API, pentru fișierele temei, e mult mai strict: cam 2 cereri pe secundă. Descărcarea fișierelor de temă cu 12 workeri în paralel a fost strangulată în masă și a pierdut tăcut majoritatea fișierelor; la aproximativ 3 cereri pe secundă, cu reîncercare și pauze crescătoare, au venit toate cele 369.

Lângă limitatorul de rată stau două verificări. O mutație care întoarce `200` cu un array `userErrors` nevid n-a făcut nimic, și nu aruncă nicio excepție. Iar o recitire imediat după scrierea unui fișier de temă poate întoarce conținutul vechi câteva secunde, așa că verificatorul nostru reîncearcă citirea de până la 5 ori, cu pauze tot mai lungi, și raportează „nu am putut confirma”, nu „a fost respins”.

## Unde am greșit

Am tratat orice 401 ca token expirat, când cauza cea mai des întâlnită era un token de alt tip sau un marcaj trimis în locul tokenului. Am presupus că un redeploy repară tokenurile vechi din flota de aplicații, când doar ștergerea sesiunii salvate a făcut-o. Și după ce cursa dintre reînnoiri și arderea în modul doar citire au fost reparate în producție, am continuat să-i avertizăm pe colegi despre ele ca riscuri active; acum, înainte de avertisment, verificăm versiunea care rulează de fapt.

## Limitele metodei

Duratele de viață și termenele de mai sus sunt valorile publicate de Shopify la data scrierii și se pot schimba; verifică documentația curentă înainte să te bazezi pe ele. Fereastra de grație am observat-o într-un singur incident. Lacătul pe magazin previne cursele din propriul sistem, nu pe cele dintre două sisteme diferite care țin credențialele aceleiași aplicații. Și nimic din toate astea nu ajută când comerciantul dezinstalează aplicația: atunci singura reparație e o instalare nouă.

## Lista de verificare

**1.** O singură funcție întoarce un token valid; scripturile nu citesc registrul direct. **2.** Tokenurile permanente de aplicație custom nu intră în codul de reînnoire. **3.** Cere tokenuri care expiră cu `expiring=1` în ambele fluxuri. **4.** Salvează noul refresh token la fiecare reînnoire; la erori trecătoare reîncearcă cu același. **5.** Procesele doar de citire nu au voie să reînnoiască. **6.** Șterge un token doar sub lacătul magazinului, după recitire. **7.** La 401, reînnoiește o dată, reîncearcă o dată, apoi eșuează vizibil. **8.** Respectă găleata, citește `userErrors` și verifică scrierile prin recitire cu reîncercări.

## Întrebări și răspunsuri

### De ce întoarce Shopify Admin API eroarea 401 Invalid API key or access token?

Din experiența noastră, cea mai des întâlnită cauză a unui 401 de la Shopify nu e un token expirat, ci tipul greșit de token, de pildă o valoare statică veche pentru un magazin al cărui token se rotește, sau un marcaj trimis în locul unui token emis din credențialele de client. Verifică întâi cum se autentifică magazinul, abia apoi reînnoiește ceva. Dacă tipul e corect, un 401 la reînnoire înseamnă că accesul e mort și cineva trebuie să redeschidă aplicația din adminul magazinului.

### Cât durează un token offline Shopify care expiră?

Un token offline Shopify care expiră durează 1 oră. Vine cu un refresh token, cu prefixul shprt_, valabil 90 de zile și utilizabil o singură dată: fiecare reînnoire întoarce un token de acces nou și un refresh token nou, iar cel nou trebuie salvat. Joburile din fundal și webhook-urile depind de el, fiindcă nu au o sesiune de utilizator din care să obțină alt token.

### Am nevoie de tokenuri care expiră pentru o aplicație Shopify custom?

Nu. Conform regulii publicate de Shopify, aplicațiile custom sunt scutite; aplicațiile publice create începând cu 1 aprilie 2026 trebuie să folosească tokenuri offline care expiră, iar cele publice mai vechi trebuie să migreze până la 1 ianuarie 2027. Scutirea se termină la distribuția publică: la noi, fiecare apel Admin API a întors 403 imediat după alegerea distribuției publice, până când aplicația a cerut tokenuri cu expiring=1.

### Ce trebuie să facă codul când eșuează reînnoirea unui token Shopify?

Tratează un 401 la apelul de reînnoire ca final: accesul e mort, oprește reîncercările și anunță un om. Tratează erorile 5xx, 429 și cele de rețea ca trecătoare și reîncearcă cu același refresh token, fiindcă Shopify reîntoarce același răspuns timp de 1 oră. Nu șterge niciodată refresh tokenul salvat fără lacăt pe magazin și fără o recitire, altfel o reînnoire paralelă poate pierde tokenul abia emis.

### Cum evit erorile de limită de rată în Shopify GraphQL?

Citește extensions.cost.throttleStatus la fiecare răspuns și încetinește înainte să se golească găleata. Pe planul standard, găleata are 1000 de puncte și se reumple cu 100 pe secundă; interogările costă implicit 1 punct, mutațiile 10. La HTTP 429 respectă Retry-After. REST Asset API e mult mai strict, cam 2 cereri pe secundă, așa că lucrul cu fișierele temei se face secvențial, cu reîncercări.

## Cum se citează

**Citare:** Going Stellar (2026). *Cum expiră și cum se reînnoiesc tokenurile Shopify Admin API: tokenuri permanente, tokenuri care expiră și capcanele reînnoirii*. GOING STELLAR S.R.L.. https://goingstellar.ro/ro/metode/tokenuri-shopify-admin-api-expirare-reinnoire/

```bibtex
@misc{goingstellar2026shopify,
  title  = {Cum expiră și cum se reînnoiesc tokenurile Shopify Admin API: tokenuri permanente, tokenuri care expiră și capcanele reînnoirii},
  author = {{Going Stellar}},
  year   = {2026},
  url    = {https://goingstellar.ro/ro/metode/tokenuri-shopify-admin-api-expirare-reinnoire/},
  note   = {2026-10-11}
}
```

Licență. Se poate cita liber, cu atribuire.

## Mai există și

- Pagina în HTML: https://goingstellar.ro/ro/metode/tokenuri-shopify-admin-api-expirare-reinnoire/
- Același articol în engleză: https://goingstellar.ro/methods/shopify-admin-api-tokens-expiring-refresh/
