snow · 2026.5.27 13:45 · 조회 1
Logto 멀티 테넌트 (Organizations)
LogtoIAMB2BOrganizations멀티테넌트
Logto의 Organizations 기능은 B2B SaaS 서비스에서 고객사(테넌트)별로 사용자와 권한을 독립적으로 관리할 수 있도록 지원합니다. 하나의 Logto 테넌트 안에서 여러 "조직(Organization)"을 운영하는 구조입니다.
6.1 조직(Organization) 개념
멀티 테넌트 구조 이해
Logto Tenant (your-tenant-id.logto.app)
├── Organization: 고객사 A (org-a)
│ ├── Member: user1@a.com (Admin)
│ ├── Member: user2@a.com (Member)
│ └── Member: user3@a.com (Viewer)
├── Organization: 고객사 B (org-b)
│ ├── Member: admin@b.com (Admin)
│ └── Member: dev@b.com (Member)
└── Organization: 고객사 C (org-c)
└── Member: ceo@c.com (Admin)
각 Organization은 독립적인 멤버십과 역할 체계를 가집니다. 동일 사용자가 여러 Organization에 다른 역할로 소속될 수 있습니다.
주요 개념
| 개념 | 설명 |
|---|---|
| Organization | 고객사/팀/워크스페이스 단위 |
| Organization Role | Organization 내 역할 (admin, member 등) |
| Organization Scope | 조직 컨텍스트의 권한 |
| Just-in-Time | 특정 이메일 도메인으로 가입 시 자동 Organization 배정 |
6.2 Organization 설정 및 생성
Organization 기능 활성화
Admin Console → Organizations → Set up organization 클릭 후 기능을 활성화합니다.
Organization Role 템플릿 정의
Admin Console → Organizations → Organization template
| Role 이름 | Organization Scope | 설명 |
|---|---|---|
admin | read:data, write:data, manage:members, manage:settings | 조직 전체 관리 |
member | read:data, write:data | 일반 작업 가능 |
viewer | read:data | 읽기 전용 |
Management API로 Organization 생성
1const org = await fetch(2 'https://your-tenant-id.logto.app/api/organizations',3 {4 method: 'POST',5 headers: {6 Authorization: `Bearer ${token}`,7 'Content-Type': 'application/json',8 },9 body: JSON.stringify({10 name: '고객사 A',11 description: 'A사 전용 워크스페이스',12 customData: { plan: 'enterprise', contractEnd: '2026-12-31' },13 }),14 }15).then(r => r.json());16 17console.log('Organization ID:', org.id);6.3 멤버 관리
Organization에 멤버 추가
1await fetch(2 `https://your-tenant-id.logto.app/api/organizations/${orgId}/users`,3 {4 method: 'POST',5 headers: {6 Authorization: `Bearer ${token}`,7 'Content-Type': 'application/json',8 },9 body: JSON.stringify({ userIds: ['user-id-1', 'user-id-2'] }),10 }11);멤버에게 Organization Role 할당
1await fetch(2 `https://your-tenant-id.logto.app/api/organizations/${orgId}/users/${userId}/roles`,3 {4 method: 'POST',5 headers: {6 Authorization: `Bearer ${token}`,7 'Content-Type': 'application/json',8 },9 body: JSON.stringify({ organizationRoleIds: ['role-id-admin'] }),10 }11);Just-in-Time (JIT) 프로비저닝
Admin Console → Organizations → 해당 Organization → Just-in-time provisioning
이메일 도메인: company-a.com
기본 역할: member
user@company-a.com으로 가입하는 모든 사용자는 자동으로 해당 Organization의 member로 추가됩니다.
6.4 Organization 컨텍스트 토큰 획득
React SDK에서 Organization 토큰 요청
1import { useLogto } from '@logto/react';2 3function useOrgAccess(organizationId: string) {4 const { getOrganizationToken } = useLogto();5 6 const callOrgApi = async (path: string) => {7 const token = await getOrganizationToken(organizationId);8 9 return fetch(`https://api.yourapp.com${path}`, {10 headers: {11 Authorization: `Bearer ${token}`,12 'X-Organization-Id': organizationId,13 },14 });15 };16 17 return { callOrgApi };18}Organization 토큰 payload 예시
1{2 "sub": "user-id",3 "organization_id": "org-a",4 "organization_roles": ["admin"],5 "scope": "read:data write:data manage:members manage:settings",6 "aud": "https://api.yourapp.com",7 "iss": "https://your-tenant-id.logto.app/oidc"8}백엔드에서 Organization 권한 검증
1function requireOrgRole(role: string) {2 return (req: Request, res: Response, next: NextFunction) => {3 const orgRoles = req.user?.organization_roles ?? [];4 if (!orgRoles.includes(role)) {5 return res.status(403).json({ error: 'Insufficient organization role' });6 }7 next();8 };9}10 11router.delete(12 '/orgs/:orgId/members/:userId',13 requireAuth,14 requireOrgRole('admin'),15 async (req, res) => {16 await OrgService.removeMember(req.params.orgId, req.params.userId);17 res.status(204).send();18 }19);6.5 사용자의 Organization 목록 조회
1import { LogtoConfig, UserScope } from '@logto/react';2 3const config: LogtoConfig = {4 endpoint: 'https://your-tenant-id.logto.app',5 appId: 'your-app-id',6 scopes: [UserScope.Organizations, UserScope.Profile, UserScope.Email],7};1function OrganizationSelector() {2 const { fetchUserInfo } = useLogto();3 const [orgs, setOrgs] = useState([]);4 5 useEffect(() => {6 fetchUserInfo().then(user => setOrgs(user.organizations ?? []));7 }, []);8 9 return (10 <div>11 <h3>워크스페이스 선택</h3>12 {orgs.map(org => (13 <button key={org.id} onClick={() => selectOrg(org.id)}>14 {org.name} ({org.role})15 </button>16 ))}17 </div>18 );19}다음 단계
멀티 테넌트 설정이 완료되었습니다. 로그인 화면을 브랜드에 맞게 커스터마이징하는 방법을 알아보십시오.
다음: Logto 로그인 UI 커스터마이징 — 브랜딩, CSS, 커스텀 도메인
참고: Logto Organizations — https://docs.logto.io/organizations
댓글
아직 댓글이 없습니다.
댓글을 작성하려면 로그인이 필요합니다.