ავტორიზაციის ნაკადი (Authorization Code + PKCE)

ეს გვერდი აღწერს სრულ ციკლს — გადამისამართებიდან ტოკენების მიღებამდე და განახლებამდე. თუ OIDC ბიბლიოთეკას იყენებთ, ის ამ ნაბიჯების უმეტესობას ავტომატურად გააკეთებს; აქ ჩამოწერილია ის, რაც უნდა იცოდეთ კონფიგურაციისა და შეცდომების დამუშავებისთვის.

ნაბიჯი 1 — PKCE წყვილის გენერაცია

ყოველი შესვლისთვის აგენერირებთ ახალ შემთხვევით code_verifier-ს (43–128 სიმბოლო, [A-Za-z0-9-._~]) და ითვლით code_challenge = BASE64URL(SHA256(code_verifier)). Verifier რჩება თქვენთან (სესიაში), challenge მიდის authorize მოთხოვნაში.

PKCE სავალდებულოა ყველა client-ისთვის, მათ შორის confidential-ისთვისაც. მხარდაჭერილია მხოლოდ S256 მეთოდი — plain ან challenge-ის გარეშე მოთხოვნა უარყოფილი იქნება invalid_request შეცდომით.

ნაბიჯი 2 — გადამისამართება authorize endpoint-ზე

GET {issuer}/oauth/authorize

ბრაუზერს (არა სერვერიდან, არა iframe-ში) გადაამისამართებთ GET {issuer}/oauth/authorize-ზე შემდეგი query პარამეტრებით:

ველი სავალდებულო აღწერა
response_type კი ყოველთვის code.
client_id კი თქვენი client-ის იდენტიფიკატორი.
redirect_uri რეკომენდებული რეგისტრირებული მისამართებიდან ერთ-ერთი, ზუსტი დამთხვევით. თუ client-ს მხოლოდ ერთი მისამართი აქვს, შეიძლება გამოტოვოთ — თუმცა რეკომენდებულია ყოველთვის გადმოცემა.
scope კი სივრცით გამოყოფილი სია. openid სავალდებულოა; დაამატეთ profile email phone. იხ. „მომხმარებლის მონაცემები“.
state რეკომენდებული შემთხვევითი მნიშვნელობა CSRF-ისგან დასაცავად. უცვლელად დაგიბრუნდებათ — შეამოწმეთ დამთხვევა.
nonce რეკომენდებული შემთხვევითი მნიშვნელობა, რომელიც id_token-ში nonce claim-ად ბრუნდება. იცავს ტოკენის განმეორებითი გამოყენებისგან.
code_challenge კი ნაბიჯ 1-ში გამოთვლილი challenge.
code_challenge_method კი ყოველთვის S256.
prompt არა none — ფორმას არ აჩვენებს: თუ მომხმარებელი უკვე შესულია, კოდი ბრუნდება მაშინვე, თუ არა — შეცდომა login_required. login — პაროლს ხელახლა ითხოვს. select_account — ანგარიშის არჩევის ეკრანს აჩვენებს. create — პირდაპირ რეგისტრაციის ფორმას ხსნის (მაგ. ღილაკისთვის „INEX-ზე რეგისტრაცია“).
max_age არა წამებში: რამდენი ხნის წინანდელი შესვლა ჩაითვლება მისაღებად. უფრო ძველი შესვლისას პაროლი ხელახლა მოითხოვება (prompt=none-თან ერთად — შეცდომა login_required). ფაქტობრივი დრო id_token-ში auth_time-ად ბრუნდება.
login_hint არა ელ. ფოსტა ან ტელეფონი, რომლითაც შესვლის ველი წინასწარ შეივსება.
ui_locales არა INEX ID-ის გვერდების ენა: ka, en ან ru.

ნაბიჯი 3 — დაბრუნება redirect_uri-ზე

წარმატების შემთხვევაში მომხმარებელი ბრუნდება {redirect_uri}?code=…&state=… მისამართზე. ჯერ შეამოწმეთ state, შემდეგ გაცვალეთ კოდი. კოდი ერთჯერადია და მოკლევადიანი (რამდენიმე წუთი) — გაცვლა დაუყოვნებლივ მოახდინეთ.

შეცდომის შემთხვევაში იმავე მისამართზე მოდის ?error=…&error_description=…&state=…:

error როდის რა უნდა გააკეთოთ
access_denied მომხმარებელმა დააჭირა „უკან“ / გააუქმა შესვლა. დააბრუნეთ მომხმარებელი შესვლის გვერდზე, შეცდომის ჩვენების გარეშე.
login_required prompt=none, ბრაუზერში INEX ID-ის აქტიური სესია არ არის (ან max_age-ზე ძველია). გაუშვით ჩვეულებრივი (ინტერაქტიული) შესვლა.
account_selection_required prompt=none, ბრაუზერში რამდენიმე ანგარიშია შესული. გაუშვით შესვლა prompt=select_account-ით.
invalid_request აკლია ან არასწორია პარამეტრი (მაგ. PKCE, მეთოდი არაა S256). შეასწორეთ მოთხოვნა — ეს თქვენი მხარის შეცდომაა.
invalid_scope მოთხოვნილი scope არ არსებობს. გამოიყენეთ მხოლოდ დოკუმენტირებული scope-ები.
თუ client_id ან redirect_uri არასწორია, INEX ID უსაფრთხოების მიზნით მომხმარებელს თქვენთან არ აბრუნებს და შეცდომას საკუთარ გვერდზე აჩვენებს.

ნაბიჯი 4 — კოდის გაცვლა ტოკენებზე

POST {issuer}/oauth/token

თქვენი სერვერიდან აგზავნით POST {issuer}/oauth/token მოთხოვნას, Content-Type: application/x-www-form-urlencoded. Confidential client ავთენტიფიცირდება client_secret-ით — ან body-ში (client_secret_post), ან HTTP Basic ჰედერით (client_secret_basic). Public client secret-ს არ აგზავნის.

ველი სავალდებულო აღწერა
grant_type კი authorization_code.
code კი callback-ში მიღებული კოდი.
redirect_uri კი ზუსტად იგივე, რაც authorize მოთხოვნაში იყო.
client_id კი თქვენი client-ის იდენტიფიკატორი.
client_secret პირობითი მხოლოდ confidential client-ისთვის (თუ Basic ჰედერს არ იყენებთ).
code_verifier კი ნაბიჯ 1-ში შენახული verifier.

პასუხი 200 OK

ველი ტიპი აღწერა
token_type string ყოველთვის Bearer.
expires_in integer access token-ის სიცოცხლის ხანგრძლივობა წამებში. გამოიყენეთ ეს მნიშვნელობა — ნუ ჩაწერთ კოდში ფიქსირებულ დროს.
access_token string ტოკენი /userinfo-ის გამოსაძახებლად.
refresh_token string ახალი access token-ის მისაღებად (იხ. ნაბიჯი 6). ინახეთ მხოლოდ სერვერზე, დაშიფრულად.
id_token string (JWT) ხელმოწერილი JWT მომხმარებლის იდენტობით. ბრუნდება მაშინ, როცა scope-ში openid იყო.
შეცდომისას ბრუნდება HTTP 400/401 და JSON {"error": "…", "error_description": "…"}. ყველაზე ხშირი: invalid_grant (კოდი ვადაგასულია, უკვე გამოყენებულია, verifier ან redirect_uri არ ემთხვევა), invalid_client (არასწორი secret), unsupported_grant_type (მხარდაჭერილია მხოლოდ authorization_code და refresh_token).

ნაბიჯი 5 — id_token-ის შემოწმება

id_token არის RS256-ით ხელმოწერილი JWT. ნდობამდე აუცილებლად შეამოწმეთ:

  • ხელმოწერა — საჯარო გასაღებით {issuer}/oauth/jwks-დან; გასაღები შეარჩიეთ ჰედერის kid-ით. JWKS დაქეშეთ, ხოლო უცნობი kid-ის შემთხვევაში ხელახლა ჩამოტვირთეთ (გასაღების როტაცია).
  • iss — ზუსტად ემთხვევა issuer-ს (მაგ. https://id.inex.ge, ბოლოში /-ის გარეშე).
  • aud — ემთხვევა თქვენს client_id-ს.
  • exp — ტოკენი ვადაგასული არ არის (id_token მოქმედებს 1 საათი).
  • nonce — ემთხვევა authorize მოთხოვნაში გაგზავნილს.

sub

sub არის მომხმარებლის მუდმივი იდენტიფიკატორი (UUID). ის არასოდეს იცვლება და ერთნაირია ყველა client-ისთვის. სწორედ ის უნდა შეინახოთ და გამოიყენოთ მომხმარებლის საიდენტიფიკაციოდ — არა ელ. ფოსტა ან ტელეფონი, რომლებიც შეიძლება შეიცვალოს (ტელეფონი, ამასთან, უნიკალურიც არ არის).

ნაბიჯი 6 — ტოკენის განახლება

access token-ის ვადის ამოწურვისას აგზავნით POST {issuer}/oauth/token-ს: grant_type=refresh_token, refresh_token, client_id (+ client_secret confidential client-ისთვის). პასუხი იგივე ფორმისაა: ახალი access token, ახალი refresh token და ახალი id_token (nonce/auth_time-ის გარეშე).

Refresh token როტირდება: ყოველი განახლებისას ძველი ბათილდება და უნდა შეინახოთ ახალი. ძველის ხელახლა გამოყენება აბრუნებს invalid_grant-ს. თუ ერთსა და იმავე მომხმარებელზე პარალელური მოთხოვნები გაქვთ, განახლება ერთი lock-ით დაიცავით, რომ ორმა პროცესმა ერთი და იგივე refresh token ერთდროულად არ გამოიყენოს.

ჩუმი შემოწმება (prompt=none)

თუ გინდათ მომხმარებელი ავტომატურად შეიყვანოთ, როცა ის INEX ID-ზე უკვე შესულია (მაგ. სხვა INEX-ის სერვისიდან მოსული), გააგზავნეთ ჩვეულებრივი authorize მოთხოვნა prompt=none-ით. ან მაშინვე დაბრუნდება კოდით, ან login_required / account_selection_required შეცდომით — ფორმა მომხმარებელს არ გამოუჩნდება.

შემდეგი შემდეგი ნაბიჯი: მომხმარებლის მონაცემები (scope-ები და claim-ები)