# Backend Auth

> NestJS JWT authentication and RBAC: JwtGuard, OptionalJwtGuard, AuthorizeCoreUsersGuard, CoreUserType decorator, login/register, Google/Apple OAuth, token invalidation. Use when protecting routes, implementing auth, roles, guards, or login endpoints.

- Skill: `xmuhameed/backend-auth` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add xmuhameed/backend-auth`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xmuhameed/backend-auth/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: xmuhameed (https://skillmd.com/u/xmuhameed)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/xmuhameed/backend-auth

---


# Backend Auth & Authorization

## Roles

`CUSTOMER`, `ADMIN`, `EDITOR`, `ORDER_HANDLER`, `ORDER_DRIVER`, `ACCOUNTANT`, `MARKETER`

## Guards

| Guard | Use |
|-------|-----|
| `JwtGuard` | Required auth — 401 if missing |
| `OptionalJwtGuard` | Public endpoint, `@GetUser()` may be null |
| `AuthorizeCoreUsersGuard` | Role check — always after JwtGuard |

## Protect Endpoint

```typescript
@UseGuards(JwtGuard, AuthorizeCoreUsersGuard)
@ApiBearerAuth()
@CoreUserType([CoreUserEnum.ADMIN, CoreUserEnum.EDITOR])
@Post('create-category')
async create(@Body() dto: CreateDto, @GetUser() user: user) { ... }
```

## Access Matrix (typical module)

| Endpoint | Guards |
|----------|--------|
| `get-all-*` | None (public) |
| `get-*` | `OptionalJwtGuard` (view tracking) |
| `create/update/delete-*` | Jwt + Authorize + `@CoreUserType([ADMIN, EDITOR])` |
| Admin-only | `@CoreUserType([ADMIN])` |
| Customer | `@CoreUserType([CUSTOMER])` |

## JWT Flow

1. Login → `signJwtToken(userId, email, role)` — 90-day HS256
2. Request → Bearer header → `JwtStrategy.validate()` → DB user lookup by role
3. `@GetUser()` → `request.user`

## Auth Endpoints

| Route | Access |
|-------|--------|
| POST `/auth/login` | Public |
| POST `/auth/register` | Public |
| POST `/auth/oauth/google` | Public |
| POST `/auth/oauth/apple` | Public |
| GET `/auth/get-profile` | JwtGuard |
| PATCH `/auth/update-profile` | JwtGuard |
| POST `/auth/logout` | JwtGuard + token blacklist |
| POST `/auth/register-admin` | Admin only |

## OptionalJwtGuard

```typescript
@UseGuards(OptionalJwtGuard)
@Get('get-category')
async getOne(@GetUser() user: user) { ... }  // user may be null
```

## Token Invalidation

`expired_tokens` table — logout inserts token; optional guard rejects blacklisted tokens.

## Imports

```typescript
import { JwtGuard, AuthorizeCoreUsersGuard, OptionalJwtGuard } from '../auth/guard';
import { CoreUserEnum, CoreUserType, GetUser } from '../auth/decorator';
```

## Password

bcrypt hash on register; `comparePassword` on login. Never return password in responses.

## Common Mistakes

- `AuthorizeCoreUsersGuard` without `JwtGuard` — always stack Jwt first
- `@CoreUserType` without guard — guard reads metadata, both required
- Trusting JWT role without DB lookup — strategy must re-fetch user

More: [reference.md](reference.md)

