RealWorld API Authorization Model: How Article Access and Modification Are Governed
The RealWorld API implements a role-based, token-driven authorization system where JSON Web Tokens (JWT) authenticate users, and strict author ownership checks in utils/auth.ts enforce that only article authors can update or delete content.
The gothinkster/realworld repository demonstrates production-grade API patterns through a Medium-clone application. Its RealWorld API authorization model governs every interaction with article resources, balancing open read access with secure write protections that verify both authentication and resource ownership.
How the RealWorld API Authorization Model Works
JWT Token Generation and Validation
According to the source code, the authorization flow begins at authentication. When users log in via /api/users/login or sign up via /api/users, the system generates a JWT using the helper defined in utils/generate-token.ts. This token must be included in subsequent requests using the Authorization: Token <jwt> header format.
The auth middleware exported from utils/auth.ts processes every protected route. It performs three critical operations:
- Extracts the token from the
Authorizationheader - Verifies the token signature and expiration
- Attaches the decoded
userIdtoreq.userfor downstream handlers
If the token is missing or invalid, the middleware immediately returns a 401 Unauthorized response, preventing access to restricted endpoints.
Article Operation Permissions
Public Read Access (Unauthenticated)
Reading articles requires no authentication. Endpoints like GET /api/articles and GET /api/articles/:slug query the database directly through handlers that bypass the auth middleware entirely. This design allows anonymous users to browse content while protecting modification capabilities.
# Fetch public articles without authentication
curl https://api.realworld.io/api/articles?limit=10&offset=0
Creating Articles (Authenticated Users Only)
To create an article, users must provide a valid JWT. The creation handler in routes/api/articles/index.post.ts passes requests through the auth.ts middleware, which validates the token and injects the userId into req.user. The system then stores the article with authorId set to this authenticated user, establishing ownership for future authorization checks.
TOKEN=$(cat token.txt)
curl -X POST https://api.realworld.io/api/articles \
-H "Content-Type: application/json" \
-H "Authorization: Token $TOKEN" \
-d '{
"article": {
"title": "Understanding RealWorld Auth",
"description": "A short description",
"body": "Full article body …",
"tagList": ["auth","api"]
}
}'
Updating and Deleting Articles (Author-Only)
The strictest authorization rules apply to article modifications. Handlers in routes/api/articles/[slug]/index.put.ts and routes/api/articles/[slug]/index.delete.ts perform ownership verification after JWT validation. They fetch the target article and compare article.authorId against req.user.id. If the IDs do not match, the system throws a 403 Forbidden error, blocking the operation even for authenticated users.
# Update (author only)
TOKEN=$(cat token.txt)
curl -X PUT https://api.realworld.io/api/articles/how-to-use-auth \
-H "Content-Type: application/json" \
-H "Authorization: Token $TOKEN" \
-d '{"article": {"title": "Updated Title"}}'
# Delete (author only)
curl -X DELETE https://api.realworld.io/api/articles/how-to-use-auth \
-H "Authorization: Token $TOKEN"
Secondary Resource Authorization
Favoriting Articles
The favorite endpoints at POST /api/articles/:slug/favorite and DELETE /api/articles/:slug/favorite require authentication but impose no ownership restrictions. Any logged-in user may favorite any article. The handlers in routes/api/articles/[slug]/favorite/index.post.ts and index.delete.ts use the JWT-derived userId to create or remove favorite relationships.
Comment Operations
Comment authorization follows a similar pattern to articles. Creating comments via POST /api/articles/:slug/comments requires only authentication, with the handler storing the comment with an authorId matching the JWT user. However, deleting comments via DELETE /api/articles/:slug/comments/:id enforces author ownership, verifying that req.user.id matches the comment's authorId before removal.
Key Authorization Files in the Repository
Understanding the RealWorld API authorization model requires examining these specific source files:
utils/generate-token.ts: JWT generation logic for login/signup responsesutils/auth.ts: Express middleware that validates tokens and populatesreq.usermodels/article.model.ts: Database schema defining theauthorIdrelationshiproutes/api/articles/index.post.ts: Article creation handlerroutes/api/articles/[slug]/index.put.ts: Article update handler with ownership checksroutes/api/articles/[slug]/index.delete.ts: Article deletion handler with ownership checksroutes/api/articles/[slug]/favorite/index.post.ts: Favorite creation handlerroutes/api/articles/[slug]/favorite/index.delete.ts: Favorite removal handlerroutes/api/articles/[slug]/comments/*.ts: Comment creation and deletion handlers
Summary
- The RealWorld API authorization model combines JWT token authentication with resource ownership verification to secure article management.
- Public read operations require no authentication, while write operations demand valid JWT tokens passed via the
Authorization: Token <jwt>header. - The
auth.tsmiddleware validates tokens and attachesuserIdto requests, returning401 Unauthorizedfor invalid credentials. - Article updates and deletions enforce strict author ownership by comparing
article.authorIdagainstreq.user.id, returning403 Forbiddenfor non-authors. - Comments and favorites use tiered permissions: creation requires only authentication, while comment deletion requires comment authorship.
Frequently Asked Questions
Do I need authentication to read articles in the RealWorld API?
No. The GET /api/articles and GET /api/articles/:slug endpoints are publicly accessible without any authentication headers. The handlers query the database directly without passing through the auth.ts middleware, allowing anonymous users to browse content freely.
How does the RealWorld API verify article ownership during updates?
The update handler in routes/api/articles/[slug]/index.put.ts first validates the JWT through the auth middleware, then fetches the target article from the database. It performs a strict equality check between article.authorId and req.user.id. If the values match, the update proceeds; otherwise, the API returns a 403 Forbidden error.
Can any authenticated user favorite an article?
Yes. Favoriting operations only require a valid JWT token to identify the user. The handlers in the favorite directory accept any authenticated request and create or delete favorite relationships using the JWT-derived userId, regardless of article ownership.
What happens if I try to delete another user's comment?
The deletion handler returns a 403 Forbidden error. For comment deletion at DELETE /api/articles/:slug/comments/:id, the system verifies that the authorId stored on the comment matches the req.user.id from the JWT. Only matching authors can delete their own comments, while authenticated non-authors are blocked from removing others' content.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →