188 lines
9.1 KiB
TypeScript
188 lines
9.1 KiB
TypeScript
/* eslint-disable */
|
||
import React, { useState, useEffect } from "react"
|
||
|
||
const SDK_SCRIPT_SNIPPET = `<script src="https://account.hamsoo.me/sdk/identity-widget.js"></script>`
|
||
const SIGNIN_ROOT_SNIPPET = `<div id="hamsoo-signin-root"></div>`
|
||
const INIT_SNIPPET = `HamsooID.init({
|
||
client_id: "your-client-id",
|
||
redirect_uri: "https://your-site.com/callback",
|
||
scope: "openid profile email",
|
||
response_mode: "web_message", // برای پاپآپ موبایلی
|
||
onSuccess: ({ code, state }) => {
|
||
// Exchange code for tokens at: POST /oauth/token
|
||
console.log("Authorization code:", code, "State:", state)
|
||
},
|
||
onError: (err) => {
|
||
console.error("Sign in error:", err)
|
||
},
|
||
})`
|
||
const TOKEN_EXCHANGE_SNIPPET = `import requests
|
||
|
||
resp = requests.post(
|
||
"https://account.hamsoo.me/oauth/token",
|
||
data={
|
||
"grant_type": "authorization_code",
|
||
"code": "<code-from-onSuccess>",
|
||
"redirect_uri": "https://your-site.com/callback",
|
||
"client_id": "your-client-id",
|
||
"client_secret": "<client-secret-from-dashboard>",
|
||
},
|
||
)
|
||
tokens = resp.json()
|
||
print(tokens["access_token"])`
|
||
|
||
export default function DevelopersPage() {
|
||
const [sdkLoaded, setSdkLoaded] = useState(false)
|
||
|
||
useEffect(() => {
|
||
const script = document.createElement("script")
|
||
script.src = "/sdk/identity-widget.js"
|
||
script.async = true
|
||
script.onload = () => setSdkLoaded(true)
|
||
script.onerror = () => console.error("Failed to load Hamsoo SDK")
|
||
document.head.appendChild(script)
|
||
}, [])
|
||
|
||
return (
|
||
<section className="py-12 bg-gray-50 dark:bg-gray-900">
|
||
<div className="max-w-5xl mx-auto px-4">
|
||
<h2 className="text-3xl font-bold text-[#1f2733] mb-8 text-center">
|
||
مستندات توسعهدهندگان / Developer Documentation
|
||
</h2>
|
||
|
||
<div className="mb-12">
|
||
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">۵ دقیقه شروع کنید / Quickstart</h3>
|
||
<ol className="list-decimal list-inside space-y-3 max-w-xl mx-auto text-[#1f2733]">
|
||
<li>
|
||
<strong>1. ثبت اپلیکیشن:</strong> در داشبورد هوامله (https://account.hamsoo.me) یک application ثبت کنید. <code>client_id</code> و <code>redirect_uris</code> را ثبت کنید. گام scopes: <code>openid profile email phone</code>.
|
||
</li>
|
||
<li>
|
||
<strong>2. SDK را اضافه کنید:</strong> کد زیر را در هدر یا انتهای <code>body</code> سایت خود قرار دهید:
|
||
<pre className="bg-[#f4f6fb] p-3 rounded text-sm overflow-x-auto"><code className="language-html">{SDK_SCRIPT_SNIPPET}</code></pre>
|
||
</li>
|
||
<li>
|
||
<strong>3. دکمه را جایگذاری کنید:</strong>
|
||
<pre className="bg-[#f4f6fb] p-3 rounded text-sm"><code className="language-html">{SIGNIN_ROOT_SNIPPET}</code></pre>
|
||
<pre className="bg-[#f4f6fb] p-3 rounded text-sm mt-2"><code className="language-javascript">{INIT_SNIPPET}</code></pre>
|
||
</li>
|
||
<li>
|
||
<strong>4. backend: تبادل code برای توکن:</strong>
|
||
<pre className="bg-[#f4f6fb] p-3 rounded text-sm mt-2"><code className="language-python">{TOKEN_EXCHANGE_SNIPPET}</code></pre>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
|
||
<div className="mb-12">
|
||
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">مرجع SDK / SDK Reference</h3>
|
||
<table className="w-full text-sm border-collapse border-border mt-4">
|
||
<thead>
|
||
<tr className="border-b border-border">
|
||
<th className="text-left p-2">روش / Method</th>
|
||
<th className="text-left p-2">توضیحات / Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2 font-medium">HamsooID.init({"{ options }"})</td>
|
||
<td className="p-2">ابزار SDK را مقداردهی و دکمه را render میکند</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2 font-medium">onSuccess({"{ code, state }"})</td>
|
||
<td className="p-2">وقتی کاربر با موفقیت احراز هویت میشود، این تابع صدا زده میشود</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2 font-medium">onError({"{ error }"})</td>
|
||
<td className="p-2">وقتی احراز هویت شکست خورد، این تابع صدا زده میشود</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">ارائهدهنده API / API Endpoints</h3>
|
||
<p className="text-[#6b7280] mb-6">
|
||
تمام endpoints روی دامنه <code>account.hamsoo.me</code> قابل دسترسی هستند.
|
||
</p>
|
||
<table className="w-full text-sm border-collapse border-border">
|
||
<thead>
|
||
<tr className="border-b border-border">
|
||
<th className="text-left p-2">Endpoint</th>
|
||
<th className="text-left p-2">روش / Method</th>
|
||
<th className="text-left p-2">توضیحات / Description</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2">GET /.well-known/openid-configuration</td>
|
||
<td className="p-2">GET</td>
|
||
<td className="p-2">OpenID Discovery document</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2">GET /oauth/jwks</td>
|
||
<td className="p-2">GET</td>
|
||
<td className="p-2">JSON Web Key Set for JWT verification</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2">GET /oauth/authorize</td>
|
||
<td className="p-2">GET/POST</td>
|
||
<td className="p-2">Authorization endpoint (PKCE + consent)</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2">POST /oauth/token</td>
|
||
<td className="p-2">POST</td>
|
||
<td className="p-2">Exchange code for tokens (PKCE)</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2">GET /oauth/userinfo</td>
|
||
<td className="p-2">GET</td>
|
||
<td className="p-2">User claims (scope-dependent)</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2">GET /sso/login</td>
|
||
<td className="p-2">GET</td>
|
||
<td className="p-2">Central SSO login page (account chooser + MFA + Passkey)</td>
|
||
</tr>
|
||
<tr className="hover:bg-[#f0f4f8]">
|
||
<td className="p-2">POST /api/v1/security/pow/challenge</td>
|
||
<td className="p-2">POST</td>
|
||
<td className="p-2">Self-hosted proof-of-work challenge (anti-bot)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">مباحث امنیتی / Security Best Practices</h3>
|
||
<ul className="list-disc list-inside text-[#1f2733] space-y-2">
|
||
<li>
|
||
<strong>حتماً PKCE استفاده کنید:</strong> هر JWT Authorization Request باید شامل code verifier و challenge باشد.
|
||
</li>
|
||
<li>
|
||
<strong>پارامتر state را ولید کنید:</strong> همیشه پاسخ state را با درخواست اصلی مقایسه کنید.
|
||
</li>
|
||
<li>
|
||
<strong>redirect_uri را تأیید کنید:</strong> redirect_uri ثبتشده است و با redirect_uris اپلیکیشن تطابق دارد.
|
||
</li>
|
||
<li>
|
||
<strong>response_mode=web_message برای پاپآپها استفاده کنید:</strong> این روش redirect صفحه کامل را حذف میکند و تجربه modal ایجاد میکند.
|
||
</li>
|
||
<li>
|
||
<strong>Self-hosted PoW برای لاگین:</strong> هر درخواست لاگین باید challenge را حل کند (سبک ALTCHA) که فعالیت bot را کاهش میدهد.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div>
|
||
<h3 className="text-xl font-semibold text-[#2f6df6] mb-4">مدیریت اپلیکیشن / App Management</h3>
|
||
<p className="text-[#6b7280] mb-6">
|
||
اپلیکیشنهای خود را در پورتال مدیریت کنید:{" "}
|
||
<a href="https://account.hamsoo.me/admin/applications" className="underline text-[#2f6df6]" target="_blank" rel="noreferrer">
|
||
account.hamsoo.me/admin/applications
|
||
</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)
|
||
}
|