# How AiToEarn Handles User Authentication and Authorization: JWT and OAuth 2.0 Architecture

> Learn how AiToEarn security architecture uses JWT for user authentication and OAuth 2.0 for authorization. Discover its NestJS backend implementation.

- Repository: [yikart/AiToEarn](https://github.com/yikart/AiToEarn)
- Tags: architecture
- Published: 2026-05-12

---

**AiToEarn implements a two-layer security architecture using JWT-based user authentication for API access and OAuth 2.0 for platform authorization, with guards, decorators, and interceptors handling token validation across the NestJS backend.**

The `yikart/AiToEarn` repository provides a comprehensive example of modern authentication patterns in a full-stack TypeScript application. This guide examines how the backend validates user sessions through JSON Web Tokens while managing third-party platform credentials through OAuth 2.0 flows.

## JWT-Based User Authentication

The backend API relies on stateless JWT authentication to identify users across requests. After successful credential validation, the system issues signed tokens that subsequent requests must present in the `Authorization` header.

### Token Generation and Validation

The authentication flow begins at the `/login` endpoint. The `AitoearnAuthService` class provides the `generateToken()` method to create signed JWTs following successful credential verification.

```typescript
// project/aitoearn-backend/apps/aitoearn-server/src/core/user/login.controller.ts
@Post('login')
async login(@Body() dto: LoginDto) {
  const userInfo = await this.authService.validateUser(dto);
  const token = this.authService.generateToken(userInfo);   // → JWT
  const tokenInfo = this.authService.decodeToken(token);   // → { userId, role, … }
  return { token, tokenInfo };
}

```

### Guarding Routes with AitoearnAuthGuard

Protected endpoints use the `AitoearnAuthGuard` located in [`project/aitoearn-backend/libs/aitoearn-auth/src/aitoearn-auth.guard.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-backend/libs/aitoearn-auth/src/aitoearn-auth.guard.ts). This guard extracts the Bearer token from the `Authorization` header, verifies its signature, and throws `UnauthorizedException` for missing, malformed, or expired tokens.

```typescript
// project/aitoearn-backend/apps/aitoearn-server/src/core/user/user.controller.ts
@Get('profile')
@UseGuards(AitoearnAuthGuard)                 // ← checks JWT
async getProfile(@GetToken() token: TokenInfo) {
  // token.userId is guaranteed to be a valid, authenticated user
  return this.userService.getProfile(token.userId);
}

```

### Accessing Token Data with Decorators

The `@GetToken()` custom decorator, defined in [`project/aitoearn-backend/libs/aitoearn-auth/src/aitoearn-auth.decorator.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-backend/libs/aitoearn-auth/src/aitoearn-auth.decorator.ts), injects the decoded token payload (`TokenInfo`) directly into controller method parameters. This gives handlers immediate access to `userId`, role, and other claims without manual parsing.

## OAuth 2.0 Platform Authorization

Beyond user identity, AiToEarn manages authorization for external content platforms like XHS, Douyin, and LinkedIn through OAuth 2.0 credential exchange.

### Credential Storage Schema

Platform tokens persist in MongoDB according to the schema defined in [`project/aitoearn-backend/libs/mongodb/src/schemas/oauth2-credential.schema.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-backend/libs/mongodb/src/schemas/oauth2-credential.schema.ts). The document structure stores `accessToken`, `refreshToken`, `expiresAt`, and the associated `userId`, enabling secure automated API calls on behalf of users.

### Frontend OAuth Flow Implementation

The **Channel Manager** frontend component orchestrates the OAuth handshake. The process uses a temporary task ID pattern: the frontend requests an authorization URL, opens a popup, and polls for completion.

```typescript
// project/aitoearn-web/src/components/ChannelManager/channelManagerStore.ts
async startAuth(platform: string) {
  const { authData } = await getAuthUrl(platform); // → { taskId, url }
  this.authState = { taskId: authData.taskId, authUrl: authData.url };
  const popup = window.open(authData.url);
  this.pollAuthStatus();
}

```

Once the user authenticates with the external platform, the backend stores the credential via `OAuth2CredentialRepository`. The frontend detects completion through polling:

```typescript
private async pollAuthStatus() {
  const result = await checkAuthStatus(this.authState.platform, this.authState.taskId);
  if (result.success) {
    this.authState = initialAuthState; // clear state
    // credential now stored on the backend; UI can reflect the linked account
  }
}

```

## Request Context Propagation

To make authenticated user data available throughout the request lifecycle, AiToEarn uses the `RequestContextInterceptor` in [`project/aitoearn-backend/libs/common/src/interceptors/request-context.interceptor.ts`](https://github.com/yikart/AiToEarn/blob/main/project/aitoearn-backend/libs/common/src/interceptors/request-context.interceptor.ts). This interceptor attaches the user context to the request object, allowing downstream services to access authentication state without explicit parameter passing.

## Summary

- **JWT Validation**: The `AitoearnAuthGuard` validates Bearer tokens on every protected request, throwing `UnauthorizedException` for invalid sessions.
- **Token Injection**: The `@GetToken()` decorator provides controller methods immediate access to decoded JWT payloads containing `userId` and role information.
- **OAuth Management**: Platform credentials store in MongoDB with expiration tracking, while the frontend Channel Manager handles OAuth flows via task ID polling.
- **Context Availability**: `RequestContextInterceptor` ensures authenticated user data propagates through the entire request chain.

## Frequently Asked Questions

### How does AiToEarn validate incoming JWT tokens?

The `AitoearnAuthGuard` extracts the token from the `Authorization` header, verifies its cryptographic signature, and validates the payload structure. If the token is missing, malformed, or expired, the guard immediately throws an `UnauthorizedException`, preventing access to protected endpoints.

### Where does AiToEarn store OAuth 2.0 tokens for connected platforms?

Platform credentials persist in MongoDB collections defined by [`oauth2-credential.schema.ts`](https://github.com/yikart/AiToEarn/blob/main/oauth2-credential.schema.ts) within the `libs/mongodb` library. Each document contains the `accessToken`, `refreshToken`, `expiresAt` timestamp, and the `userId` to associate the credential with the correct account.

### How does the frontend know when OAuth authorization completes?

The Channel Manager store utilizes a polling mechanism. After opening the OAuth provider URL in a popup, it repeatedly calls `checkAuthStatus(taskId)` until the backend confirms successful token exchange. The `taskId` uniquely identifies the pending authorization session during this asynchronous handshake.

### Can controllers access user data outside of the JWT decorator?

Yes. The `RequestContextInterceptor` attaches the authenticated user to the request object, making user information available to any downstream service or interceptor in the request pipeline. This provides an alternative to method parameter decorators for scenarios requiring implicit context access.