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 RoleOrganization 내 역할 (admin, member 등)
Organization Scope조직 컨텍스트의 권한
Just-in-Time특정 이메일 도메인으로 가입 시 자동 Organization 배정

6.2 Organization 설정 및 생성

Organization 기능 활성화

Admin Console → OrganizationsSet up organization 클릭 후 기능을 활성화합니다.

Organization Role 템플릿 정의

Admin Console → OrganizationsOrganization template

Role 이름Organization Scope설명
adminread:data, write:data, manage:members, manage:settings조직 전체 관리
memberread:data, write:data일반 작업 가능
viewerread: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

댓글

아직 댓글이 없습니다.

댓글을 작성하려면 로그인이 필요합니다.