Skip to content

Commit d0e4d29

Browse files
committed
chore: improve api docs page
improve to have a readme.io look and feel
1 parent a8d0ff5 commit d0e4d29

8 files changed

Lines changed: 11369 additions & 521 deletions

File tree

docs-page/index.html

Lines changed: 40 additions & 436 deletions
Large diffs are not rendered by default.

docs-page/nginx.conf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ server {
1414
add_header X-XSS-Protection "1; mode=block" always;
1515
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
1616

17-
# Allow swagger-ui and Google Fonts to load resources
18-
add_header Content-Security-Policy "default-src 'self' https://unpkg.com; style-src 'self' 'unsafe-inline' https://unpkg.com https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; script-src 'self' 'unsafe-inline' https://unpkg.com; img-src 'self' data: https:; connect-src 'self' https://api.prostaff.gg https://unpkg.com;" always;
17+
# Allow Scalar CDN and API to load resources
18+
add_header Content-Security-Policy "default-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: https:; connect-src 'self' https://api.prostaff.gg https://cdn.jsdelivr.net; worker-src blob:;" always;
1919

2020
location / {
2121
try_files $uri $uri/ /index.html;
@@ -43,7 +43,7 @@ server {
4343
add_header X-Content-Type-Options "nosniff" always; # nosemgrep: generic.nginx.security.header-redefinition.header-redefinition
4444
add_header X-XSS-Protection "1; mode=block" always; # nosemgrep: generic.nginx.security.header-redefinition.header-redefinition
4545
add_header Referrer-Policy "strict-origin-when-cross-origin" always; # nosemgrep: generic.nginx.security.header-redefinition.header-redefinition
46-
add_header Content-Security-Policy "default-src 'self' https://unpkg.com; style-src 'self' 'unsafe-inline' https://unpkg.com https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; script-src 'self' 'unsafe-inline' https://unpkg.com; img-src 'self' data: https:; connect-src 'self' https://api.prostaff.gg https://unpkg.com;" always; # nosemgrep: generic.nginx.security.header-redefinition.header-redefinition
46+
add_header Content-Security-Policy "default-src 'self' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data: https:; connect-src 'self' https://api.prostaff.gg https://cdn.jsdelivr.net; worker-src blob:;" always; # nosemgrep: generic.nginx.security.header-redefinition.header-redefinition
4747
}
4848

4949
gzip on;

docs/guides/authentication.md

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
# Authentication
2+
3+
ProStaff uses JWT (JSON Web Token) for authentication. Every request to a protected
4+
endpoint must include a valid access token in the `Authorization` header.
5+
6+
There are two distinct auth paths: **user auth** (for staff members — owner, admin,
7+
coach, analyst) and **player auth** (for individual player access). They use separate
8+
login endpoints and produce tokens with different payloads and permission scopes.
9+
10+
---
11+
12+
## 1. Login and obtain tokens
13+
14+
### User login
15+
16+
```
17+
POST /api/v1/auth/login
18+
```
19+
20+
Request body:
21+
22+
```json
23+
{
24+
"email": "coach@yourteam.gg",
25+
"password": "yourpassword"
26+
}
27+
```
28+
29+
Successful response (200):
30+
31+
```json
32+
{
33+
"message": "Login successful",
34+
"data": {
35+
"user": {
36+
"id": "a1b2c3d4-...",
37+
"email": "coach@yourteam.gg",
38+
"full_name": "Jane Coach",
39+
"role": "coach"
40+
},
41+
"organization": {
42+
"id": "e5f6g7h8-...",
43+
"name": "Team Valor"
44+
},
45+
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
46+
"refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
47+
"expires_in": 86400,
48+
"token_type": "Bearer"
49+
}
50+
}
51+
```
52+
53+
### Player login
54+
55+
Players authenticate with a separate endpoint using a `player_email` field
56+
(distinct from the staff `email` field):
57+
58+
```
59+
POST /api/v1/auth/player-login
60+
```
61+
62+
Request body:
63+
64+
```json
65+
{
66+
"player_email": "player@example.com",
67+
"password": "playerpassword"
68+
}
69+
```
70+
71+
Successful response (200):
72+
73+
```json
74+
{
75+
"message": "Login realizado com sucesso",
76+
"data": {
77+
"player": {
78+
"id": "p1q2r3s4-...",
79+
"summoner_name": "Faker#KR1",
80+
"role": "mid",
81+
"organization_id": "e5f6g7h8-..."
82+
},
83+
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
84+
"refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
85+
"expires_in": 86400,
86+
"token_type": "Bearer"
87+
}
88+
}
89+
```
90+
91+
Player access must be explicitly enabled by staff before a player can log in.
92+
Attempting to log in with a disabled account returns 401 `INVALID_CREDENTIALS`.
93+
94+
---
95+
96+
## 2. Using the Authorization header
97+
98+
Include the access token in every request to a protected endpoint:
99+
100+
```
101+
Authorization: Bearer <access_token>
102+
```
103+
104+
The header value must start with `Bearer ` (case-insensitive) followed by the token.
105+
Requests without this header, or with a malformed header, receive:
106+
107+
```json
108+
{
109+
"error": {
110+
"code": "UNAUTHORIZED",
111+
"message": "Missing authentication token"
112+
}
113+
}
114+
```
115+
116+
---
117+
118+
## 3. Token lifetime
119+
120+
| Token | Lifetime | Configurable via ENV |
121+
|---------------|-----------------|-----------------------------------|
122+
| access_token | 24 hours | `JWT_EXPIRATION_HOURS` (default 24) |
123+
| refresh_token | 7 days | `JWT_REFRESH_EXPIRATION_DAYS` (default 7) |
124+
125+
---
126+
127+
## 4. Refreshing the access token
128+
129+
When the access token expires, use the refresh token to obtain a new pair without
130+
requiring the user to log in again. Refresh tokens are single-use: each call to
131+
this endpoint invalidates the submitted refresh token and returns a fresh pair.
132+
133+
```
134+
POST /api/v1/auth/refresh
135+
```
136+
137+
Request body:
138+
139+
```json
140+
{
141+
"refresh_token": "eyJhbGciOiJIUzI1NiJ9..."
142+
}
143+
```
144+
145+
Successful response (200):
146+
147+
```json
148+
{
149+
"message": "Token refreshed successfully",
150+
"data": {
151+
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
152+
"refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
153+
"expires_in": 86400,
154+
"token_type": "Bearer"
155+
}
156+
}
157+
```
158+
159+
If the refresh token has already been used or is invalid, the response is 401:
160+
161+
```json
162+
{
163+
"error": {
164+
"code": "INVALID_REFRESH_TOKEN",
165+
"message": "Refresh token already used"
166+
}
167+
}
168+
```
169+
170+
---
171+
172+
## 5. Logout
173+
174+
Logout blacklists the current access token in Redis so it cannot be reused before
175+
its natural expiry. Send the refresh token in the body to also invalidate it — this
176+
is strongly recommended to prevent session reuse after logout.
177+
178+
```
179+
POST /api/v1/auth/logout
180+
```
181+
182+
Request body (optional but recommended):
183+
184+
```json
185+
{
186+
"refresh_token": "eyJhbGciOiJIUzI1NiJ9..."
187+
}
188+
```
189+
190+
Successful response (200):
191+
192+
```json
193+
{
194+
"message": "Logout successful",
195+
"data": {}
196+
}
197+
```
198+
199+
Omitting the refresh token is not an error, but the refresh token will remain valid
200+
until its natural expiry. An attacker who obtained it could create new sessions.
201+
202+
---
203+
204+
## 6. What happens when a token expires
205+
206+
A request with an expired access token receives 401:
207+
208+
```json
209+
{
210+
"error": {
211+
"code": "UNAUTHORIZED",
212+
"message": "Token has expired"
213+
}
214+
}
215+
```
216+
217+
When you receive this response, call `POST /api/v1/auth/refresh` with your stored
218+
refresh token. If the refresh token has also expired or been revoked, the user must
219+
log in again with their credentials.
220+
221+
---
222+
223+
## 7. User auth vs Player auth
224+
225+
| Aspect | User token | Player token |
226+
|---------------------|-------------------------------------------|---------------------------------------------|
227+
| Login endpoint | `POST /api/v1/auth/login` | `POST /api/v1/auth/player-login` |
228+
| Credential field | `email` | `player_email` |
229+
| Token payload | `user_id`, `organization_id`, `role` | `entity_type: "player"`, `player_id`, `organization_id` |
230+
| Roles available | owner, admin, coach, analyst | player (limited scope) |
231+
| Pundit enforcement | Full policy evaluation | Restricted to player-specific endpoints |
232+
| Staff endpoints | Accessible (role-dependent) | Blocked (`require_user_auth!` guard) |
233+
234+
Refresh and logout endpoints work the same way for both token types.
235+
236+
---
237+
238+
## 8. Complete cURL flow: login, request, refresh
239+
240+
```bash
241+
# Step 1 — login and capture tokens
242+
RESPONSE=$(curl -s -X POST https://api.prostaff.gg/api/v1/auth/login \
243+
-H "Content-Type: application/json" \
244+
-d '{"email":"coach@yourteam.gg","password":"yourpassword"}')
245+
246+
ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.data.access_token')
247+
REFRESH_TOKEN=$(echo "$RESPONSE" | jq -r '.data.refresh_token')
248+
249+
# Step 2 — authenticated request
250+
curl -s https://api.prostaff.gg/api/v1/players \
251+
-H "Authorization: Bearer $ACCESS_TOKEN"
252+
253+
# Step 3 — refresh when token expires (201 Unauthorized triggers this)
254+
NEW_TOKENS=$(curl -s -X POST https://api.prostaff.gg/api/v1/auth/refresh \
255+
-H "Content-Type: application/json" \
256+
-d "{\"refresh_token\":\"$REFRESH_TOKEN\"}")
257+
258+
ACCESS_TOKEN=$(echo "$NEW_TOKENS" | jq -r '.data.access_token')
259+
REFRESH_TOKEN=$(echo "$NEW_TOKENS" | jq -r '.data.refresh_token')
260+
261+
# Step 4 — logout
262+
curl -s -X POST https://api.prostaff.gg/api/v1/auth/logout \
263+
-H "Authorization: Bearer $ACCESS_TOKEN" \
264+
-H "Content-Type: application/json" \
265+
-d "{\"refresh_token\":\"$REFRESH_TOKEN\"}"
266+
```
267+
268+
---
269+
270+
## See also
271+
272+
- [Multi-tenancy](multi-tenancy.md) — how organization_id is enforced on every request
273+
- [Error codes](error-codes.md) — full list of error responses
274+
- [Quick start](quickstart.md) — end-to-end walkthrough from registration to first request

0 commit comments

Comments
 (0)