> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 인증 설정하기

> Sonamu에서 better-auth 기반 인증 시스템 구축하기

Sonamu에서 사용자 인증을 설정하는 방법을 알아봅니다. Sonamu는 [better-auth](https://www.better-auth.com/)를 기반으로 한 통합 인증 시스템을 제공합니다.

## 인증 시스템 개요

<CardGroup cols={2}>
  <Card title="better-auth 통합" icon="shield-halved">
    검증된 인증 라이브러리

    이메일/비밀번호, 소셜 로그인
  </Card>

  <Card title="자동 엔티티 생성" icon="wand-magic-sparkles">
    CLI로 엔티티 자동 생성

    User, Session, Account, Verification
  </Card>

  <Card title="Context 기반" icon="diagram-project">
    요청마다 사용자 정보

    Sonamu.getContext()
  </Card>

  <Card title="Guards 시스템" icon="lock">
    선언적 권한 제어

    @api guards 옵션
  </Card>
</CardGroup>

## 빠른 시작

### 1. 인증 엔티티 생성

better-auth가 필요로 하는 엔티티들을 자동으로 생성합니다:

```bash theme={null}
pnpm sonamu auth generate
```

이 명령어는 4개의 엔티티를 생성합니다:

| 엔티티          | 테이블           | 설명                                                   |
| ------------ | ------------- | ---------------------------------------------------- |
| User         | users         | 사용자 정보 (id, name, email, email\_verified, image)     |
| Session      | sessions      | 세션 정보 (id, token, expires\_at, user\_id)             |
| Account      | accounts      | 소셜 계정 연결 (id, provider\_id, access\_token, user\_id) |
| Verification | verifications | 이메일 인증 등 (id, identifier, value, expires\_at)        |

<Info>
  기존 엔티티가 있으면 누락된 필드만 추가됩니다. 필드 타입이 변경된 경우 자동으로 업데이트됩니다.
</Info>

### 2. 마이그레이션 실행

엔티티 생성 후 마이그레이션을 실행합니다:

```bash theme={null}
pnpm sonamu migrate generate
pnpm sonamu migrate run
```

### 3. 인증 설정

`sonamu.config.ts`에서 인증을 활성화합니다:

```typescript theme={null}
// sonamu.config.ts
import type { SonamuConfig } from "sonamu";

export default {
  // ... 다른 설정들
  server: {
    auth: {
      emailAndPassword: { enabled: true },
    },
  },
} satisfies SonamuConfig;
```

이것으로 기본적인 이메일/비밀번호 인증이 활성화됩니다.

## API 엔드포인트

better-auth가 제공하는 API 엔드포인트들이 자동으로 등록됩니다:

| 경로                        | 메서드  | 설명       |
| ------------------------- | ---- | -------- |
| `/api/auth/sign-up/email` | POST | 이메일 회원가입 |
| `/api/auth/sign-in/email` | POST | 이메일 로그인  |
| `/api/auth/sign-out`      | POST | 로그아웃     |
| `/api/auth/get-session`   | GET  | 현재 세션 조회 |

## Context에서 사용자 정보 접근

인증된 사용자 정보는 Context를 통해 접근합니다:

```typescript theme={null}
import { Sonamu } from "sonamu";

class UserModelClass extends BaseModelClass {
  @api({ httpMethod: "GET", guards: ["user"] })
  async me(): Promise<UserSubsetA | null> {
    const { user, session } = Sonamu.getContext();

    if (!user) return null;

    // user.id, user.email, user.name 등 접근 가능
    return this.findById("A", user.id);
  }
}
```

### AuthContext 타입

```typescript theme={null}
type AuthContext = {
  /** 현재 로그인한 사용자 (null이면 미인증) */
  user: User | null;
  /** 현재 세션 정보 (null이면 미인증) */
  session: Session | null;
};
```

`User`와 `Session` 타입은 better-auth에서 제공합니다.

## Guards를 통한 접근 제어

### 기본 Guard 사용

```typescript theme={null}
class UserModelClass extends BaseModelClass {
  // 로그인 필수
  @api({ httpMethod: "GET", guards: ["user"] })
  async getProfile() {
    const { user } = Sonamu.getContext();
    return { userId: user.id };
  }

  // 관리자 권한 필요
  @api({ httpMethod: "DELETE", guards: ["admin"] })
  async deleteUser(id: string) {
    // 관리자만 실행 가능
  }
}
```

### guardHandler 구현

Guard 로직은 `sonamu.config.ts`의 `guardHandler`에서 구현합니다:

```typescript theme={null}
// sonamu.config.ts
import { Sonamu } from "sonamu";

export default {
  server: {
    auth: {
      emailAndPassword: { enabled: true },
    },
    apiConfig: {
      guardHandler: (guard, request, api) => {
        const { user } = Sonamu.getContext();

        switch (guard) {
          case "user":
            if (!user) {
              throw new Error("로그인이 필요합니다");
            }
            break;

          case "admin":
            // User 엔티티에 role 필드 추가 필요
            if (!user || (user as any).role !== "admin") {
              throw new Error("관리자만 접근 가능합니다");
            }
            break;

          case "query":
            // 모든 사용자 허용
            break;
        }
      },
    },
  },
} satisfies SonamuConfig;
```

## 소셜 로그인 설정

### Google 로그인

```typescript theme={null}
// sonamu.config.ts
export default {
  server: {
    auth: {
      emailAndPassword: { enabled: true },
      socialProviders: {
        google: {
          clientId: process.env.GOOGLE_CLIENT_ID!,
          clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
        },
      },
    },
  },
} satisfies SonamuConfig;
```

### GitHub 로그인

```typescript theme={null}
// sonamu.config.ts
export default {
  server: {
    auth: {
      emailAndPassword: { enabled: true },
      socialProviders: {
        github: {
          clientId: process.env.GITHUB_CLIENT_ID!,
          clientSecret: process.env.GITHUB_CLIENT_SECRET!,
        },
      },
    },
  },
} satisfies SonamuConfig;
```

## 사용자 역할 추가

better-auth의 기본 User 엔티티에는 `role` 필드가 없습니다. 권한 기반 인증이 필요하면 User 엔티티에 직접 추가하세요:

### 1. Sonamu UI에서 필드 추가

User 엔티티에 `role` 필드를 추가합니다:

* 이름: `role`
* 타입: `string`
* 기본값: `"user"`

### 2. Enum 추가 (선택사항)

```json theme={null}
{
  "enums": {
    "UserRole": {
      "user": "일반 사용자",
      "admin": "관리자",
      "manager": "매니저"
    }
  }
}
```

### 3. guardHandler에서 역할 확인

```typescript theme={null}
guardHandler: (guard, request, api) => {
  const { user } = Sonamu.getContext();

  if (guard === "admin") {
    if (!user || (user as any).role !== "admin") {
      throw new Error("관리자 권한이 필요합니다");
    }
  }
},
```

## 클라이언트 통합

### React에서 사용

```typescript theme={null}
import { createAuthClient } from "better-auth/react";

export const authClient = createAuthClient({
  baseURL: "http://localhost:4000/api/auth",
});

// 회원가입
await authClient.signUp.email({
  email: "user@example.com",
  password: "password123",
  name: "홍길동",
});

// 로그인
await authClient.signIn.email({
  email: "user@example.com",
  password: "password123",
});

// 로그아웃
await authClient.signOut();

// 현재 세션 조회
const session = await authClient.getSession();
```

## 필드 매핑

better-auth는 camelCase를 사용하지만, Sonamu는 snake\_case를 사용합니다. 다음 필드들이 자동으로 매핑됩니다:

| better-auth     | Sonamu           |
| --------------- | ---------------- |
| `emailVerified` | `email_verified` |
| `createdAt`     | `created_at`     |
| `userId`        | `user_id`        |
| `expiresAt`     | `expires_at`     |

## 체크리스트

인증 설정 후 확인 사항:

* [ ] `pnpm sonamu auth generate` 실행
* [ ] 마이그레이션 생성 및 적용
* [ ] `sonamu.config.ts`에 `server.auth` 설정
* [ ] `guardHandler` 구현
* [ ] Context에서 user/session 접근 확인
* [ ] 권한 기반 인증 필요 시 User 엔티티에 role 추가

## 다음 단계

<CardGroup cols={2}>
  <Card title="세션 관리" icon="clock-rotate-left" href="/ko/api-development/authentication/session-management">
    세션과 토큰 관리
  </Card>

  <Card title="Context" icon="diagram-project" href="/ko/api-development/context/sonamu-context">
    Context 자세히 알아보기
  </Card>

  <Card title="@api 데코레이터" icon="at" href="/ko/api-development/creating-apis/api-decorator">
    API 데코레이터 옵션
  </Card>

  <Card title="에러 처리" icon="triangle-exclamation" href="/ko/api-reference/exceptions/sonamu-error">
    인증 에러 처리
  </Card>
</CardGroup>
