From e96ad6964dc2f3672673246383f91052094b895d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Muhammet=20=C5=9EAFAK?= <104234499+muhammetsafak@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:08:25 +0300 Subject: [PATCH] apiUserPassword uygulama parolasi oldu (spec 1.2.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apiUserPassword artik geliştiricinin developer portal HESAP PAROLASI degil, portalin uygulama basina verdigi bir parola. Wire format ve tum metod imzalari aynen duruyor — degisen yalnizca degerin nereden geldigi. Eskiden bu deger portal hesap parolasiydi: geliştiricinin sahip oldugu her uygulama tarafindan paylasiliyordu, sizmasi portal hesabinin tamamini acikta birakiyordu ve dondurulmesi tum entegrasyonlari birden kiriyordu. Artik uygulamaya ozel, 32 karakter [A-Za-z0-9], portaldaki uygulama sayfasindan kopyalanabiliyor ve tek basina yenilenebiliyor. - DESIGN.md 5.1: kimlik bilgisi tablosuna dorduncu satir (Application password) - DESIGN.md 12.2: yeni gecis bolumu - README + kaynak doc-comment'leri guncellendi Not: 32 karakterlik parola sunucunun parola-gucu tavsiyesine takilmiyor; password_policy.must_change partner girislerinde her zaman false. --- DESIGN.md | 45 +++++++++++++++++++++++++++++++---- README.md | 7 +++--- src/Resource/AuthResource.php | 7 +++--- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index c4e7ecd..efca139 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -9,7 +9,11 @@ > Wire contract is derived from the BulutklinikAPI source (Laravel 8.12, > OAuth2/Passport) — `app/Packages/Integration/Outher` and `routes/{v3,v4}/outher.php`. -- **Spec version:** 1.1.0 — restores the `auth` group. 1.0.x wrongly claimed the +- **Spec version:** 1.2.0 — `apiUserPassword` is now a per-application password + issued by the portal, not the developer's portal account password. Wire format + and every method signature are unchanged; only where the value comes from. + See §5.1 and §12.2. + 1.1.0 restored the `auth` group. 1.0.x wrongly claimed the partner token could only be issued out of band; it is in fact obtained through the same `connectApi` password grant every other persona uses, and it is refreshable. See §5 and §12.1. @@ -201,16 +205,20 @@ Because `errorType` may be numeric (§3), guard before string-matching it. ### 5.1 Where the credentials come from -The Bulutklinik Developer Platform issues, per approved application, three things: +The Bulutklinik Developer Platform issues, per approved application, four things: | Value | Used as | |-------|---------| | **Client ID** | `apiClientId` — the OAuth2 client | | **Client Secret** | `apiSecretKey` — the OAuth2 client secret | | **Service identity** | `apiUserName` — a project-specific login, *not* the developer's e-mail | +| **Application password** | `apiUserPassword` — a per-application secret, *not* the developer's portal password | -The password is the one set when registering on the portal. Nothing here is a -ready-made bearer token: the token is **minted by calling the API**. +All four are shown on the application's page in the portal. The password is +masked but copyable, and can be regenerated there if it leaks — regenerating it +leaves the client id and secret untouched, so a leaked password can be rotated +without re-keying the integration. Nothing here is a ready-made bearer token: +the token is **minted by calling the API**. > Spec 1.0.x got this wrong. It described the token as "issued out of band" with > "no grant the SDK can drive", and therefore dropped `auth` entirely. The grant @@ -225,7 +233,7 @@ ready-made bearer token: the token is **minted by calling the API**. | `apiClientId` | ✓ | Client ID from the portal. | | `apiSecretKey` | ✓ | Client Secret from the portal. | | `apiUserName` | ✓ | The service identity. | -| `apiUserPassword` | ✓ | The portal account password. | +| `apiUserPassword` | ✓ | The application password from the portal. | | `loginMode` | ✓ | `email` (what the portal documents) \| `identity` \| `phone` \| `user_id`. | Success → `data: { access_token, refresh_token, password_policy }`. The SDK @@ -711,6 +719,33 @@ divergence here) — code and SSOT must never silently disagree. ## 12. Migration +### 12.2 From 1.1.x — `apiUserPassword` is per-application + +Nothing in the SDK surface changes: same field, same endpoint, same flow. What +changes is which secret you put in it. + +Until now the value was the developer's **portal account password** — the same +one used to sign in to the developer platform, shared by every application that +developer owned. It is now a **per-application password**, generated server-side +when the application is approved and shown on the application's page in the +portal. + +| | 1.1.x | 1.2.0 | +|---|-------|-------| +| Value | developer's portal password | per-application secret | +| Shape | whatever the developer chose | 32 chars, `[A-Za-z0-9]` | +| Scope of a leak | the portal account + every application | one application | +| Rotation | change the portal password (breaks every application) | regenerate in the portal (one application) | +| Changing the portal password | broke every integration | no effect | + +**Action:** read the application password from your application's page in the +portal and put it where your integration currently keeps the portal password. +Portal passwords stop authenticating against `connectApi` at the cutover. + +> A 32-character password no longer trips the server's password-strength +> advisory: `password_policy.must_change` is always `false` for partner +> accounts. Do not treat that field as actionable on a partner login. + ### 12.0 From 1.0.x — the `auth` group is back 1.0.x removed `auth` on the mistaken premise that a partner token could only be diff --git a/README.md b/README.md index 9dc8aaa..c06a67d 100644 --- a/README.md +++ b/README.md @@ -131,9 +131,10 @@ only it. ## Authentication -Your portal application issues a **client ID**, a **client secret** and a -project-specific **service identity**; the password is the one you set when -registering on the portal. `auth->connect()` exchanges them for an access token +Your portal application issues four values: a **client ID**, a **client secret**, +a project-specific **service identity** and an **application password**. The +password belongs to this application only — it is not your portal account +password, and you can regenerate it in the portal if it leaks. `auth->connect()` exchanges them for an access token and a refresh token: ```php diff --git a/src/Resource/AuthResource.php b/src/Resource/AuthResource.php index b3f44dd..5bdd276 100644 --- a/src/Resource/AuthResource.php +++ b/src/Resource/AuthResource.php @@ -9,9 +9,10 @@ /** * Token lifecycle. * - * The Developer Platform issues a **client id**, a **client secret** and a - * project-specific **service identity** per approved application; the password is - * the one set when registering on the portal. `connect()` exchanges those for an + * The Developer Platform issues a **client id**, a **client secret**, a + * project-specific **service identity** and an **application password** per approved + * application. The password belongs to that application only — it is not the + * developer's portal account password. `connect()` exchanges those for an * access + refresh token pair, which every other method on the client then uses. * * Neither `connect()` nor `refresh()` is partner-authenticated: they are the two