diff --git a/packages/console/src/assets/docs/guides/web-php/README.mdx b/packages/console/src/assets/docs/guides/web-php/README.mdx
index a798f3676..265c05ef0 100644
--- a/packages/console/src/assets/docs/guides/web-php/README.mdx
+++ b/packages/console/src/assets/docs/guides/web-php/README.mdx
@@ -104,40 +104,6 @@ Route::get('/callback', function () {
-
-
-Here we implement a simple home page for demonstration:
-
-- If the user is not signed in, show a sign-in button;
-- If the user is signed in, show some basic information about the user.
-
-```php
-Route::get('/', function () {
- if ($client->isAuthenticated() === false) {
- return "Not authenticated Sign in";
- }
-
- return (
- // Get local ID token claims
- $client->getIdTokenClaims()->modelDumpJson(excludeUnset: true)
- . "
"
- // Fetch user info from Logto userinfo endpoint
- $client->fetchUserInfo()->modelDumpJson(excludeUnset: true)
- . "
Sign out"
- );
-});
-```
-
-Our data models are based on [JsonModel](https://github.com/logto-io/php/blob/HEAD/docs/api/classes/Logto/Sdk/Models/JsonModel.md), which is safe to accept undefined keys while encoding or decoding JSON.
-
-Note that a field (claim) with `null` value doesn't mean the field is set. The reason may be the related scope is not requested, or the user doesn't have the field.
-
-For example, if we didn't request the `email` scope when signing in, and the `email` field will be `null`. However, if we requested the `email` scope, the `email` field will be the user's email address if available.
-
-To learn more about scopes and claims, see [Scopes and claims](https://github.com/logto-io/php/blob/HEAD/docs/tutorial.md#scopes-and-claims).
-
-
-
To clean up the Python session and Logto session, we can designate a post sign-out redierct URI. This is where Logto will redirect users after they sign out.
@@ -161,6 +127,42 @@ The post sign-out redierct URI is optional, and if not provided, the user will b
+
+
+In Logto SDK, we can use `$client->isAuthenticated()` to check the authentication status, if the user is signed in, the value will be true, otherwise, the value will be false.
+
+We also need to implement a home page for demonstration:
+
+- If the user is not signed in, show a sign-in button;
+- If the user is signed in, show some basic information about the user.
+
+```php
+Route::get('/', function () {
+ if ($client->isAuthenticated() === false) {
+ return "Not authenticated Sign in";
+ }
+
+ return (
+ // Get local ID token claims
+ json_decode($client->getIdTokenClaims())
+ . "
"
+ // Fetch user info from Logto userinfo endpoint
+ json_decode($client->fetchUserInfo())
+ . "
Sign out"
+ );
+});
+```
+
+Our data models are based on [JsonModel](https://github.com/logto-io/php/blob/master/docs/api/classes/Logto/Sdk/Models/JsonModel.md), which is safe to accept undefined keys while encoding or decoding JSON.
+
+Note that a field (claim) with `null` value doesn't mean the field is set. The reason may be the related scope is not requested, or the user doesn't have the field.
+
+For example, if we didn't request the `email` scope when signing in, and the `email` field will be `null`. However, if we requested the `email` scope, the `email` field will be the user's email address if available.
+
+To learn more about scopes and claims, see [Get user information](https://docs.logto.io/sdk/php/#get-user-information).
+
+
+
Now, you can test your application:
@@ -174,35 +176,4 @@ Now, you can test your application:
-
-
-Now, you have a working sign-in flow, but your routes are still unprotected. Per the framework you use, you can create a middleware to protect your routes. For example, in Laravel, you can create a middleware as follows:
-
-```php
-namespace App\Http\Middleware;
-
-use Closure;
-
-class LogtoAuth
-{
- public function handle($request, Closure $next)
- {
- if ($client->isAuthenticated() === false) {
- return redirect('/sign-in');
- }
- return $next($request);
- }
-}
-```
-
-Then, you can apply this middleware to your routes:
-
-```php
-Route::get('/protected', function () {
- return "Protected page";
-})->middleware(LogtoAuth::class);
-```
-
-
-
diff --git a/packages/console/src/assets/docs/guides/web-php/index.ts b/packages/console/src/assets/docs/guides/web-php/index.ts
index 186d48d29..d27684426 100644
--- a/packages/console/src/assets/docs/guides/web-php/index.ts
+++ b/packages/console/src/assets/docs/guides/web-php/index.ts
@@ -6,6 +6,10 @@ const metadata: Readonly = Object.freeze({
name: 'PHP',
description: 'Integrate Logto into your PHP web app, such as Lavarel.',
target: ApplicationType.Traditional,
+ sample: {
+ repo: 'php',
+ path: 'samples',
+ },
fullTutorial: {
title: 'Full PHP SDK tutorial',
url: 'https://docs.logto.io/sdk/php',
diff --git a/packages/console/src/assets/docs/guides/web-python/README.mdx b/packages/console/src/assets/docs/guides/web-python/README.mdx
index d7e111515..5f6ff9181 100644
--- a/packages/console/src/assets/docs/guides/web-python/README.mdx
+++ b/packages/console/src/assets/docs/guides/web-python/README.mdx
@@ -120,39 +120,6 @@ async def callback():
-
-
-Here we implement a simple home page for demonstration:
-
-- If the user is not signed in, show a sign-in button;
-- If the user is signed in, show some basic information about the user.
-
-```python
-@app.route("/")
-async def home():
- if client.isAuthenticated() is False:
- return "Not authenticated Sign in"
-
- return (
- # Get local ID token claims
- client.getIdTokenClaims().model_dump_json(exclude_unset=True)
- + "
"
- # Fetch user info from Logto userinfo endpoint
- (await client.fetchUserInfo()).model_dump_json(exclude_unset=True)
- + "
Sign out"
- )
-```
-
-Our data models are based on [pydantic](https://docs.pydantic.dev/), so you can use `model_dump_json` to dump the data model to JSON.
-
-Adding `exclude_unset=True` will exclude unset fields from the JSON output, which makes the output more precise.
-
-For example, if we didn't request the `email` scope when signing in, and the `email` field will be excluded from the JSON output. However, if we requested the `email` scope, but the user doesn't have an email address, the `email` field will be included in the JSON output with a `null` value.
-
-To learn more about scopes and claims, see [Scopes and claims](https://github.com/logto-io/python/blob/HEAD/docs/tutorial.md#scopes-and-claims).
-
-
-
To clean up the Python session and Logto session, we can designate a post sign-out redierct URI. This is where Logto will redirect users after they sign out.
@@ -179,6 +146,41 @@ async def sign_out():
+
+
+In Logto SDK, we can use `client.isAuthenticated()` to check the authentication status, if the user is signed in, the value will be true, otherwise, the value will be false.
+
+Here we also implement a simple home page for demonstration:
+
+- If the user is not signed in, show a sign-in button;
+- If the user is signed in, show some basic information about the user.
+
+```python
+@app.route("/")
+async def home():
+ if client.isAuthenticated() is False:
+ return "Not authenticated Sign in"
+
+ return (
+ # Get local ID token claims
+ client.getIdTokenClaims().model_dump_json(exclude_unset=True)
+ + "
"
+ # Fetch user info from Logto userinfo endpoint
+ (await client.fetchUserInfo()).model_dump_json(exclude_unset=True)
+ + "
Sign out"
+ )
+```
+
+Our data models are based on [pydantic](https://docs.pydantic.dev/), so you can use `model_dump_json` to dump the data model to JSON.
+
+Adding `exclude_unset=True` will exclude unset fields from the JSON output, which makes the output more precise.
+
+For example, if we didn't request the `email` scope when signing in, and the `email` field will be excluded from the JSON output. However, if we requested the `email` scope, but the user doesn't have an email address, the `email` field will be included in the JSON output with a `null` value.
+
+To learn more about scopes and claims, see [Get user information](https://docs.logto.io/sdk/python/#get-user-information).
+
+
+
Now, you can test your application:
@@ -192,34 +194,4 @@ Now, you can test your application:
-
-
-Now, you have a working sign-in flow, but your routes are still unprotected. Per the framework you use, you can create a decorator such as `@authenticated` to protect your routes. For example:
-
-```python
-from functools import wraps
-
-def authenticated(func):
- @wraps(func)
- async def wrapper(*args, **kwargs):
- if client.isAuthenticated() is False:
- return redirect("/sign-in") # Or directly call `client.signIn`
- return await func(*args, **kwargs)
-
- return wrapper
-```
-
-Then, you can use the decorator to protect your routes:
-
-```python
-@app.route("/protected")
-@authenticated
-async def protected():
- return "Protected page"
-```
-
-You can also create a middleware to achieve the same goal.
-
-
-