본문으로 건너뛰기

Vanilla JS 애플리케이션에 인증 (Authentication)을 추가하세요

Vanilla JS: @logto/browser 통합

팁:

사전 준비 사항​

설치​

선호하는 패키지 관리자를 선택하거나 CDN을 사용하여 Logto Browser SDK를 설치하세요.

npm i @logto/browser

통합​

LogtoClient 초기화​

LogtoClient 인스턴스를 가져와 설정을 전달하여 초기화하세요:

index.js
import LogtoClient from '@logto/browser';

const logtoClient = new LogtoClient({
endpoint: '<your-logto-endpoint>',
appId: '<your-application-id>',
});

endpoint와 appId는 Logto Console의 애플리케이션 세부 정보 페이지에서 찾을 수 있습니다.

리디렉션 URI 구성하기​

자세한 내용을 살펴보기 전에, 최종 사용자 경험에 대한 간단한 개요를 소개합니다. 로그인 과정은 다음과 같이 단순화할 수 있습니다:

  1. 귀하의 앱이 로그인 메서드를 호출합니다.
  2. 사용자는 Logto 로그인 페이지로 리디렉션됩니다. 네이티브 앱의 경우, 시스템 브라우저가 열립니다.
  3. 사용자가 로그인하면, 다시 귀하의 앱(리디렉션 URI로 설정됨)으로 리디렉션됩니다.

리디렉션 기반 로그인에 관하여​

  1. 이 인증 과정은 OpenID Connect (OIDC) 프로토콜을 따르며, Logto는 사용자 로그인을 보호하기 위해 엄격한 보안 조치를 시행합니다.
  2. 여러 앱이 있는 경우, 동일한 아이덴티티 제공자 (Logto)를 사용할 수 있습니다. 사용자가 한 앱에 로그인하면, Logto는 사용자가 다른 앱에 접근할 때 자동으로 로그인 과정을 완료합니다.

리디렉션 기반 로그인에 대한 이론적 배경과 이점에 대해 더 알고 싶다면, Logto 로그인 경험 설명을 참조하세요.


노트:

다음 코드 스니펫에서는, 여러분의 앱이 http://localhost:3000/ 에서 실행되고 있다고 가정합니다.

리디렉션 URI 구성​

Logto Console의 애플리케이션 세부 정보 페이지로 이동합니다. 리디렉션 URI http://localhost:3000/callback를 추가하세요.

Logto Console의 리디렉션 URI

로그인과 마찬가지로, 사용자는 공유 세션에서 로그아웃하기 위해 Logto로 리디렉션되어야 합니다. 완료되면 사용자를 다시 웹사이트로 리디렉션하면 좋습니다. 예를 들어, 로그아웃 후 리디렉션 URI 섹션에 http://localhost:3000/를 추가하세요.

그런 다음 "저장"을 클릭하여 변경 사항을 저장하세요.

리디렉션 처리하기​

사용자가 Logto에서 애플리케이션으로 다시 리디렉션된 후에도 처리해야 할 작업이 남아 있습니다. 이를 적절히 처리해 봅시다.

pages/Callback.js
const callbackHandler = async (logtoClient) => {
await logtoClient.handleSignInCallback(window.location.href);

if (!logtoClient.isAuthenticated) {
// 로그인 실패 처리
alert('로그인에 실패했습니다');
return;
}

// 로그인 성공 처리
window.location.assign('/');
};

로그인 및 로그아웃 구현하기​

logtoClient는 인증 흐름을 쉽게 관리할 수 있도록 signIn 및 signOut 메서드를 제공합니다.

노트:

.signIn()을 호출하기 전에, Admin Console 에서 Redirect URI 를 올바르게 구성했는지 확인하세요. :::

pages/Home.js
const isAuthenticated = await logtoClient.isAuthenticated();

const onClickSignIn = () => {
logtoClient.signIn('http://localhost:3000/callback');
};
const onClickSignOut = () => {
logtoClient.signOut('http://localhost:3000');
};

const button = document.createElement('button');
button.innerHTML = isAuthenticated ? 'Sign Out' : 'Sign In';
button.addEventListener('click', isAuthenticated ? onClickSignOut : onClickSignIn);

document.body.appendChild(button);

.signOut()을 호출하면 메모리와 localStorage에 존재하는 모든 Logto 데이터를 삭제합니다.

체크포인트: 애플리케이션 테스트​

이제 애플리케이션을 테스트할 수 있습니다:

  1. 애플리케이션을 실행하면 로그인 버튼이 표시됩니다.
  2. 로그인 버튼을 클릭하면 SDK가 로그인 프로세스를 초기화하고 Logto 로그인 페이지로 리디렉션합니다.
  3. 로그인 후, 애플리케이션으로 다시 리디렉션되어 사용자 ID와 로그아웃 버튼을 볼 수 있습니다.
  4. 로그아웃 버튼을 클릭하여 로그아웃합니다.

사용자 정보 가져오기​

사용자 정보 표시​

사용자의 정보를 표시하려면 logtoClient.getIdTokenClaims() 메서드를 사용할 수 있습니다. 예를 들어, Home 페이지에서:

Home.js
const userInfo = await logtoClient.getIdTokenClaims();

// ID 토큰 클레임 (Claims)을 위한 표시 테이블 생성
const table = document.createElement('table');
const thead = document.createElement('thead');
const tr = document.createElement('tr');
const thName = document.createElement('th');
const thValue = document.createElement('th');
thName.innerHTML = 'Name';
thValue.innerHTML = 'Value';
tr.append(thName, thValue);
thead.append(tr);
table.append(thead);

const tbody = document.createElement('tbody');

for (const [key, value] of Object.entries(userInfo)) {
const tr = document.createElement('tr');
const tdName = document.createElement('td');
const tdValue = document.createElement('td');
tdName.innerHTML = key;
tdValue.innerHTML = typeof value === 'string' ? value : JSON.stringify(value);
tr.append(tdName, tdValue);
tbody.append(tr);
}

table.append(tbody);

추가 클레임 (Claims) 요청​

getIdTokenClaims()에서 반환된 객체에 일부 사용자 정보가 누락된 것을 발견할 수 있습니다. 이는 OAuth 2.0 및 OpenID Connect (OIDC)가 최소 권한 원칙 (PoLP)을 따르도록 설계되었기 때문이며, Logto는 이러한 표준을 기반으로 구축되었습니다.

기본적으로 제한된 클레임 (Claim)만 반환됩니다. 더 많은 정보를 원하시면, 추가적인 스코프 (Scope)를 요청하여 더 많은 클레임에 접근할 수 있습니다.

정보:

"클레임 (Claim)"은 주체에 대해 주장하는 내용이며, "스코프 (Scope)"는 클레임의 그룹입니다. 현재의 경우, 클레임은 사용자에 대한 정보입니다.

다음은 스코프 - 클레임 관계의 비규범적 예시입니다:

팁:

"sub" 클레임은 "주체"를 의미하며, 이는 사용자의 고유 식별자 (즉, 사용자 ID)입니다.

Logto SDK는 항상 세 가지 스코프를 요청합니다: openid, profile, 그리고 offline_access.

추가 스코프 (Scopes)를 요청하려면 Logto 설정을 구성할 수 있습니다:

index.js
import LogtoClient, { UserScope } from '@logto/browser';

const logtoClient = new LogtoClient({
appId: '<your-application-id>',
endpoint: '<your-logto-endpoint>',
scopes: [UserScope.Email, UserScope.Phone],
});

그런 다음 logtoClient.getIdTokenClaims()의 반환 값에서 추가 클레임 (Claims)에 접근할 수 있습니다:

const claims = await getIdTokenClaims();
// 이제 추가 클레임 (Claims) `claims.email`, `claims.phone` 등에 접근할 수 있습니다.

네트워크 요청이 필요한 클레임​

ID 토큰의 비대화를 방지하기 위해, 일부 클레임은 네트워크 요청을 통해 가져와야 합니다. 예를 들어, custom_data 클레임은 스코프에서 요청되더라도 사용자 객체에 포함되지 않습니다. 이러한 클레임에 접근하려면, logtoClient.fetchUserInfo() 메서드를 사용할 수 있습니다:

const userInfo = await logtoClient.fetchUserInfo();
// 이제 클레임 (Claim) `userInfo.custom_data`에 접근할 수 있습니다.
이 메서드는 userinfo 엔드포인트에 요청하여 사용자 정보를 가져옵니다. 사용 가능한 스코프와 클레임에 대해 더 알고 싶다면, 스코프와 클레임 섹션을 참조하세요.

스코프 (Scopes)와 클레임 (Claims)​

Logto는 OIDC 스코프 (Scope) 및 클레임 (Claim) 규칙을 사용하여 ID 토큰 및 OIDC userinfo 엔드포인트에서 사용자 정보를 가져오기 위한 스코프 (Scope)와 클레임 (Claim)을 정의합니다. "스코프 (Scope)"와 "클레임 (Claim)" 모두 OAuth 2.0 및 OpenID Connect (OIDC) 명세에서 온 용어입니다.

표준 OIDC 클레임 (Claim)의 경우, ID 토큰에 포함되는지는 요청된 스코프 (Scope)에 의해 엄격하게 결정됩니다. 확장 클레임 (예: custom_data 및 organizations)은 커스텀 ID 토큰 설정을 통해 ID 토큰에 추가로 포함되도록 구성할 수 있습니다.

지원되는 스코프와 해당 클레임(Claim)의 목록은 다음과 같습니다:

표준 OIDC 스코프​

openid (기본값)

클레임(Claim) 이름타입설명
substring사용자의 고유 식별자

profile (기본값)

클레임(Claim) 이름타입설명
namestring사용자의 전체 이름
usernamestring사용자의 사용자명
picturestring최종 사용자의 프로필 사진 URL. 이 URL은 이미지 파일(예: PNG, JPEG, GIF 이미지 파일)을 가리켜야 하며, 이미지를 포함한 웹 페이지가 아니어야 합니다. 이 URL은 최종 사용자를 설명할 때 표시하기에 적합한 프로필 사진을 명확히 참조해야 하며, 최종 사용자가 임의로 촬영한 사진이 아니어야 합니다.
created_atnumber최종 사용자가 생성된 시간. 시간은 Unix epoch (1970-01-01T00:00:00Z) 이후 밀리초로 표시됩니다.
updated_atnumber최종 사용자의 정보가 마지막으로 업데이트된 시간. 시간은 Unix epoch (1970-01-01T00:00:00Z) 이후 밀리초로 표시됩니다.

기타 표준 클레임(Claim)에는 family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo, locale 등이 있으며, 이들은 userinfo 엔드포인트를 요청하지 않아도 profile 스코프에 포함됩니다. 위의 클레임과의 차이점은, 이 클레임들은 값이 비어 있지 않을 때만 반환되며, 위의 클레임들은 값이 비어 있으면 null을 반환합니다.

노트:

표준 클레임(Claim)과 달리, created_at 및 updated_at 클레임은 초 단위가 아닌 밀리초 단위를 사용합니다.

email

클레임(Claim) 이름타입설명
emailstring사용자의 이메일 주소
email_verifiedboolean이메일 주소가 인증되었는지 여부

phone

클레임(Claim) 이름타입설명
phone_numberstring사용자의 전화번호
phone_number_verifiedboolean전화번호가 인증되었는지 여부

address

주소 클레임(Claim)의 세부 사항은 OpenID Connect Core 1.0 을 참조하세요.

정보:

**(기본값)**으로 표시된 스코프는 항상 Logto SDK에서 요청합니다. 표준 OIDC 스코프의 클레임(Claim)은 해당 스코프가 요청될 때 항상 ID 토큰 (ID token)에 포함되며, 비활성화할 수 없습니다.

확장 스코프​

다음 스코프는 Logto에서 확장한 것으로, userinfo 엔드포인트를 통해 클레임(Claim)을 반환합니다. 이 클레임들은 Console > Custom JWT를 통해 ID 토큰 (ID token)에 직접 포함되도록 설정할 수도 있습니다. 자세한 내용은 커스텀 ID 토큰을 참고하세요.

custom_data

클레임(Claim) 이름타입설명기본적으로 ID 토큰에 포함됨
custom_dataobject사용자의 커스텀 데이터

identities

클레임(Claim) 이름타입설명기본적으로 ID 토큰에 포함됨
identitiesobject사용자의 연결된 아이덴티티
sso_identitiesarray사용자의 연결된 SSO 아이덴티티

roles

클레임(Claim) 이름타입설명기본적으로 ID 토큰에 포함됨
rolesstring[]사용자의 역할 (Role)✅

urn:logto:scope:organizations

클레임(Claim) 이름타입설명기본적으로 ID 토큰에 포함됨
organizationsstring[]사용자가 속한 조직 (Organization) ID✅
organization_dataobject[]사용자가 속한 조직 (Organization) 데이터
노트:

이러한 조직 (Organization) 클레임(Claim)은 불투명 토큰 (Opaque token)을 사용할 때도 userinfo 엔드포인트를 통해 조회할 수 있습니다. 그러나 불투명 토큰 (Opaque token)은 조직 토큰 (Organization token)으로 사용되어 조직별 리소스에 접근할 수 없습니다. 자세한 내용은 불투명 토큰 (Opaque token)과 조직 (Organization)을 참고하세요.

urn:logto:scope:organization_roles

클레임(Claim) 이름타입설명기본적으로 ID 토큰에 포함됨
organization_rolesstring[]사용자가 속한 조직 (Organization)의 역할 (Role), 형식: <organization_id>:<role_name>✅

API 리소스​

먼저 🔐 역할 기반 접근 제어 (RBAC)를 읽어 Logto RBAC의 기본 개념과 API 리소스를 적절히 설정하는 방법을 이해하는 것을 권장합니다.

Logto 클라이언트 구성하기​

API 리소스를 설정한 후, 애플리케이션에서 Logto를 구성할 때 이를 추가할 수 있습니다:

index.js
import LogtoClient from '@logto/browser';

const logtoClient = new LogtoClient({
// ...other configs
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'], // API 리소스를 추가하세요
});

각 API 리소스는 자체 권한 (스코프)을 가지고 있습니다.

예를 들어, https://shopping.your-app.com/api 리소스는 shopping:read 및 shopping:write 권한을 가지고 있으며, https://store.your-app.com/api 리소스는 store:read 및 store:write 권한을 가지고 있습니다.

이러한 권한을 요청하려면, 애플리케이션에서 Logto를 구성할 때 추가할 수 있습니다:

index.js
import LogtoClient from '@logto/browser';

const logtoClient = new LogtoClient({
// ...other configs
scopes: ['shopping:read', 'shopping:write', 'store:read', 'store:write'],
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'], // API 리소스를 추가하세요
});

스코프가 API 리소스와 별도로 정의된 것을 알 수 있습니다. 이는 OAuth 2.0을 위한 리소스 지표가 요청의 최종 스코프가 모든 대상 서비스의 모든 스코프의 데카르트 곱이 될 것이라고 명시하기 때문입니다.

따라서 위의 경우, Logto에서 정의된 스코프를 단순화할 수 있으며, 두 API 리소스 모두 접두사 없이 read 및 write 스코프를 가질 수 있습니다. 그런 다음, Logto 구성에서:

index.js
import LogtoClient, { UserScope } from '@logto/browser';

const logtoClient = new LogtoClient({
// ...other configs
scopes: ['read', 'write'],
resources: ['https://shopping.your-app.com/api', 'https://store.your-app.com/api'],
});

모든 API 리소스에 대해 read 및 write 스코프를 요청하게 됩니다.

노트:

API 리소스에 정의되지 않은 스코프를 요청해도 괜찮습니다. 예를 들어, API 리소스에 email 스코프가 없더라도 email 스코프를 요청할 수 있습니다. 사용 불가능한 스코프는 안전하게 무시됩니다.

성공적으로 로그인한 후, Logto는 사용자의 역할에 따라 API 리소스에 적절한 스코프를 발급합니다.

API 리소스를 위한 액세스 토큰 가져오기​

특정 API 리소스에 대한 액세스 토큰을 가져오려면 getAccessToken 메서드를 사용할 수 있습니다:

const accessToken = await logtoClient.getAccessToken('https://store.your-app.com/api');
console.log('액세스 토큰', accessToken);

이 메서드는 사용자가 관련 권한을 가지고 있을 때 API 리소스에 접근할 수 있는 JWT 액세스 토큰을 반환합니다. 현재 캐시된 액세스 토큰이 만료된 경우, 이 메서드는 자동으로 리프레시 토큰을 사용하여 새로운 액세스 토큰을 얻으려고 시도합니다.

조직 토큰 가져오기​

조직이 처음이라면, 시작하기 위해 🏢 조직 (다중 테넌시)을 읽어보세요.

Logto 클라이언트를 구성할 때 UserScope.Organizations 스코프를 추가해야 합니다:

index.js
import LogtoClient, { UserScope } from '@logto/browser';

const logtoClient = new LogtoClient({
// ...other configs
scopes: [UserScope.Organizations],
});

사용자가 로그인하면, 사용자에 대한 조직 토큰을 가져올 수 있습니다:

index.js
// 사용자 정보에서 organizationIds 가져오기

const claims = await logtoClient.getIdTokenClaims();
const organizationIds = claims.organizations;

/**
* 또는 ID 토큰 클레임에서 가져오기
*
* const claims = await logtoClient.getIdTokenClaims();
* const organizationIds = claims.organizations;
*/

// 조직 액세스 토큰 가져오기
if (organizationIds.length > 0) {
const organizationId = organizationIds[0];
const organizationAccessToken = await logtoClient.getOrganizationToken(organizationId);
console.log('조직 액세스 토큰', organizationAccessToken);
}

./code/_scopes-and-claims-code.mdx./code/_config-organization-code.mdx

요청 헤더에 액세스 토큰 첨부하기​

토큰을 HTTP 헤더의 Authorization 필드에 Bearer 형식 (Bearer YOUR_TOKEN)으로 넣으면 됩니다.

노트:

Bearer 토큰의 통합 흐름은 사용 중인 프레임워크나 요청자에 따라 다를 수 있습니다. 요청 Authorization 헤더를 적용하는 방법을 선택하세요.

추가 읽을거리​

엔드유저 플로우: 인증 (Authentication) 플로우, 계정 플로우, 조직 플로우 커넥터 구성하기 인가 (Authorization)