Skip to content

Commit f40d970

Browse files
huangdijiaclaude
andcommitted
Add comprehensive documentation for OAuth2 server component
- Added detailed English documentation in docs/en/components/oauth2-server.md - Added Chinese Simplified documentation in docs/zh-cn/components/oauth2-server.md - Added Chinese Traditional (Hong Kong) documentation in docs/zh-hk/components/oauth2-server.md - Added Chinese Traditional (Taiwan) documentation in docs/zh-tw/components/oauth2-server.md Documentation includes: - Complete installation and setup guide - Configuration examples and environment variables - All supported grant types with examples - API endpoints and usage examples - Available commands for client management - Event system documentation - Security best practices - Testing guidelines - Error handling reference 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 8093dc4 commit f40d970

4 files changed

Lines changed: 1464 additions & 0 deletions

File tree

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
# OAuth2 Server
2+
3+
A complete OAuth2 server implementation for Hyperf framework, based on [league/oauth2-server](https://oauth2.thephpleague.com/).
4+
5+
## Features
6+
7+
- Full OAuth2 server implementation supporting:
8+
- Client Credentials Grant
9+
- Password Grant
10+
- Refresh Token Grant
11+
- Authorization Code Grant (with PKCE support)
12+
- Built-in commands for client management
13+
- Multiple storage backends (Eloquent ORM)
14+
- Customizable token lifetimes
15+
- Scope management
16+
- Event-driven architecture
17+
18+
## Installation
19+
20+
### 1. Install via Composer
21+
22+
```bash
23+
composer require friendsofhyperf/oauth2-server
24+
```
25+
26+
### 2. Publish Configuration
27+
28+
```bash
29+
php bin/hyperf.php vendor:publish friendsofhyperf/oauth2-server
30+
```
31+
32+
### 3. Generate Encryption Keys
33+
34+
```bash
35+
# Generate private/public key pair
36+
php bin/hyperf.php oauth2:generate-keypair
37+
```
38+
39+
This will generate:
40+
- `storage/oauth2/private.key` - Private key for signing tokens
41+
- `storage/oauth2/public.key` - Public key for verifying tokens
42+
43+
### 4. Run Migrations
44+
45+
```bash
46+
php bin/hyperf.php migrate
47+
```
48+
49+
## Configuration
50+
51+
Configure your OAuth2 server in `config/autoload/oauth2-server.php`:
52+
53+
```php
54+
<?php
55+
56+
return [
57+
'authorization_server' => [
58+
'private_key' => env('OAUTH2_PRIVATE_KEY', 'storage/oauth2/private.key'),
59+
'private_key_passphrase' => env('OAUTH2_PRIVATE_KEY_PASSPHRASE'),
60+
'encryption_key' => env('OAUTH2_ENCRYPTION_KEY'),
61+
'encryption_key_type' => EncryptionKeyType::from(env('OAUTH2_ENCRYPTION_KEY_TYPE', 'plain')),
62+
'response_type' => BearerTokenResponse::class,
63+
'revoke_refresh_tokens' => true,
64+
'access_token_ttl' => new DateInterval('PT1H'),
65+
'auth_code_ttl' => new DateInterval('PT10M'),
66+
'refresh_token_ttl' => new DateInterval('P1M'),
67+
'enable_client_credentials_grant' => true,
68+
'enable_password_grant' => true,
69+
'enable_refresh_token_grant' => true,
70+
'enable_auth_code_grant' => true,
71+
'enable_implicit_grant' => false,
72+
'require_code_challenge_for_public_clients' => true,
73+
'persist_access_tokens' => true,
74+
],
75+
'resource_server' => [
76+
'public_key' => env('OAUTH2_PUBLIC_KEY', 'storage/oauth2/public.key'),
77+
'jwt_leeway' => null,
78+
],
79+
'scopes' => [
80+
'available' => ['read', 'write', 'admin'],
81+
'default' => ['read'],
82+
],
83+
];
84+
```
85+
86+
## Environment Variables
87+
88+
Set these environment variables in your `.env` file:
89+
90+
```bash
91+
# OAuth2 Keys
92+
OAUTH2_PRIVATE_KEY=storage/oauth2/private.key
93+
OAUTH2_PUBLIC_KEY=storage/oauth2/public.key
94+
OAUTH2_PRIVATE_KEY_PASSPHRASE=
95+
OAUTH2_ENCRYPTION_KEY=your-encryption-key-here
96+
97+
# Optional
98+
OAUTH2_ENCRYPTION_KEY_TYPE=plain
99+
```
100+
101+
## Available Commands
102+
103+
| Command | Description |
104+
|---------|-------------|
105+
| `oauth2:clear-expired-tokens` | Remove expired access/refresh tokens |
106+
| `oauth2:create-client` | Create a new OAuth2 client |
107+
| `oauth2:delete-client` | Delete an OAuth2 client |
108+
| `oauth2:generate-keypair` | Generate private/public key pair |
109+
| `oauth2:list-clients` | List all OAuth2 clients |
110+
| `oauth2:update-client` | Update an OAuth2 client |
111+
112+
### Creating Clients
113+
114+
Create a client for Authorization Code Grant:
115+
116+
```bash
117+
php bin/hyperf.php oauth2:create-client \
118+
--name="My Web App" \
119+
--redirect-uri="https://myapp.com/callback" \
120+
--grant-type="authorization_code" \
121+
--grant-type="refresh_token"
122+
```
123+
124+
Create a client for Password Grant:
125+
126+
```bash
127+
php bin/hyperf.php oauth2:create-client \
128+
--name="My Mobile App" \
129+
--grant-type="password" \
130+
--grant-type="refresh_token"
131+
```
132+
133+
Create a client for Client Credentials Grant:
134+
135+
```bash
136+
php bin/hyperf.php oauth2:create-client \
137+
--name="My API Service" \
138+
--grant-type="client_credentials"
139+
```
140+
141+
## API Endpoints
142+
143+
### Authorization Endpoint
144+
145+
`GET /oauth/authorize`
146+
147+
Used for Authorization Code Grant flow. Parameters:
148+
- `response_type`: Must be `code`
149+
- `client_id`: Your client ID
150+
- `redirect_uri`: Must match registered redirect URI
151+
- `scope`: Space-separated list of scopes
152+
- `state`: CSRF protection token
153+
- `code_challenge`: PKCE code challenge
154+
- `code_challenge_method`: PKCE method (usually `S256`)
155+
156+
### Token Endpoint
157+
158+
`POST /oauth/token`
159+
160+
Used to exchange authorization code for access token or use other grant types.
161+
162+
### Protected Resources
163+
164+
Use `ResourceServerMiddleware` to protect your routes:
165+
166+
```php
167+
use FriendsOfHyperf/oauth2/server/Middleware//ResourceServerMiddleware;
168+
169+
Router::addGroup('/api', function () {
170+
Router::get('user', [UserController::class, 'index']);
171+
Router::post('posts', [PostController::class, 'store']);
172+
})->add(ResourceServerMiddleware::class);
173+
```
174+
175+
## Grant Types
176+
177+
### 1. Client Credentials Grant
178+
179+
For server-to-server authentication:
180+
181+
```bash
182+
curl -X POST http://your-server/oauth/token \
183+
-H "Content-Type: application/json" \
184+
-d '{
185+
"grant_type": "client_credentials",
186+
"client_id": "your-client-id",
187+
"client_secret": "your-client-secret",
188+
"scope": "read write"
189+
}'
190+
```
191+
192+
### 2. Password Grant
193+
194+
For trusted applications (mobile apps, SPAs):
195+
196+
```bash
197+
curl -X POST http://your-server/oauth/token \
198+
-H "Content-Type: application/json" \
199+
-d '{
200+
"grant_type": "password",
201+
"client_id": "your-client-id",
202+
"client_secret": "your-client-secret",
203+
"username": "user@example.com",
204+
"password": "password",
205+
"scope": "read write"
206+
}'
207+
```
208+
209+
### 3. Authorization Code Grant
210+
211+
For web applications with user interaction:
212+
213+
**Step 1: Redirect user to authorization endpoint**
214+
215+
```
216+
https://your-server/oauth/authorize?response_type=code&client_id=your-client-id&redirect_uri=https://myapp.com/callback&scope=read&state=random-state&code_challenge=challenge&code_challenge_method=S256
217+
```
218+
219+
**Step 2: Exchange code for token**
220+
221+
```bash
222+
curl -X POST http://your-server/oauth/token \
223+
-H "Content-Type: application/json" \
224+
-d '{
225+
"grant_type": "authorization_code",
226+
"client_id": "your-client-id",
227+
"client_secret": "your-client-secret",
228+
"redirect_uri": "https://myapp.com/callback",
229+
"code_verifier": "verifier",
230+
"code": "authorization-code-from-redirect"
231+
}'
232+
```
233+
234+
### 4. Refresh Token Grant
235+
236+
To get new access tokens:
237+
238+
```bash
239+
curl -X POST http://your-server/oauth/token \
240+
-H "Content-Type: application/json" \
241+
-d '{
242+
"grant_type": "refresh_token",
243+
"client_id": "your-client-id",
244+
"client_secret": "your-client-secret",
245+
"refresh_token": "your-refresh-token",
246+
"scope": "read write"
247+
}'
248+
```
249+
250+
## Making Authenticated Requests
251+
252+
Include the access token in the Authorization header:
253+
254+
```bash
255+
curl -X GET http://your-server/api/user \
256+
-H "Authorization: Bearer your-access-token"
257+
```
258+
259+
## Events
260+
261+
The component dispatches several events you can listen to:
262+
263+
- `AuthorizationRequestResolveEvent`: When authorization request needs user approval
264+
- `UserResolveEvent`: When resolving user for password grant
265+
- `ScopeResolveEvent`: When resolving scopes
266+
- `TokenRequestResolveEvent`: When processing token requests
267+
268+
### Example Event Listener
269+
270+
```php
271+
<?php
272+
273+
namespace App\Listener;
274+
275+
use FriendsOfHyperf\Oauth2\Server\Event\UserResolveEvent;
276+
use Hyperf\Event\Annotation\Listener;
277+
278+
#[Listener]
279+
class UserResolveListener
280+
{
281+
public function listen(): array
282+
{
283+
return [
284+
UserResolveEvent::class,
285+
];
286+
}
287+
288+
public function process(object $event): void
289+
{
290+
// Validate user credentials and return user ID
291+
if ($event->getUsername() === 'admin' && $event->getPassword() === 'secret') {
292+
$event->setUserId('1');
293+
}
294+
}
295+
}
296+
```
297+
298+
## Database Tables
299+
300+
The package creates the following tables:
301+
302+
- `oauth_clients`: OAuth2 clients
303+
- `oauth_access_tokens`: Access tokens
304+
- `oauth_refresh_tokens`: Refresh tokens
305+
- `oauth_auth_codes`: Authorization codes
306+
- `oauth_personal_access_clients`: Personal access clients
307+
308+
## Customization
309+
310+
### Custom User Provider
311+
312+
Implement your own user resolution logic by listening to `UserResolveEvent`.
313+
314+
### Custom Scope Management
315+
316+
Listen to `ScopeResolveEvent` to implement custom scope logic.
317+
318+
### Custom Token Storage
319+
320+
Extend the repository classes to implement custom storage backends.
321+
322+
## Security Best Practices
323+
324+
1. Always use HTTPS in production
325+
2. Store private keys securely with proper file permissions
326+
3. Use strong encryption keys
327+
4. Implement proper CSRF protection for authorization flows
328+
5. Validate redirect URIs strictly
329+
6. Use short-lived access tokens and refresh tokens
330+
7. Implement rate limiting on token endpoints
331+
8. Log and monitor token usage
332+
333+
## Testing
334+
335+
During development, you can test the OAuth2 flow with the built-in commands:
336+
337+
```bash
338+
# Create a test client
339+
php bin/hyperf.php oauth2:create-client \
340+
--name="Test Client" \
341+
--redirect-uri="http://localhost:3000/callback" \
342+
--grant-type="authorization_code" \
343+
--grant-type="password" \
344+
--grant-type="refresh_token"
345+
346+
# List all clients
347+
php bin/hyperf.php oauth2:list-clients
348+
349+
# Clear expired tokens
350+
php bin/hyperf.php oauth2:clear-expired-tokens
351+
```
352+
353+
## Error Handling
354+
355+
Common error responses:
356+
357+
- `invalid_client`: Client authentication failed
358+
- `invalid_grant`: Invalid authorization grant
359+
- `invalid_request`: Missing required parameters
360+
- `invalid_scope`: Requested scope is invalid
361+
- `unsupported_grant_type`: Grant type not supported
362+
- `server_error`: Internal server error
363+
364+
## License
365+
366+
MIT

0 commit comments

Comments
 (0)