본문으로 건너뛰기

Device flow: Logto로 인증 (Authentication)하기

노트:

이 가이드는 Logto 콘솔에서 "네이티브" 유형의 애플리케이션을 생성하고, 인가 플로우로 device flow를 선택했다고 가정합니다.

소개 (Introduction)

OAuth 2.0 디바이스 인가 그랜트 (device flow)는 스마트 TV, 게임 콘솔, CLI 도구, IoT 기기 등 입력 기능이 제한된 디바이스를 위해 설계되었습니다. 사용자는 디바이스에서 로그인 과정을 시작하지만, 브라우저가 있는 별도의 기기(예: 휴대폰, 노트북)에서 인증 (Authentication)을 완료할 수 있습니다.

디바이스 자체에서 브라우저 기반 로그인 플로우를 처리할 수 없으므로, 디바이스는 짧은 코드와 URL을 표시합니다. 사용자는 다른 기기에서 해당 URL에 접속해 코드를 입력하고 로그인합니다. 그동안 원래의 디바이스는 인가가 완료될 때까지 Logto에 폴링합니다.

애플리케이션 자격 증명 얻기

Logto 콘솔에서 애플리케이션 상세 페이지로 이동하여 다음 자격 증명을 확인하세요:

  • App ID: 애플리케이션의 고유 식별자 (client_id라고도 함).
  • Logto endpoint: Logto 인가 서버 엔드포인트. Logto 콘솔의 "Application details"에서 확인할 수 있습니다.

Logto Cloud의 경우 엔드포인트는 https://{your-tenant-id}.logto.app 입니다.

노트:

Device flow 앱은 공개 클라이언트이므로 App Secret이 필요하지 않습니다.

디바이스 코드 요청하기

디바이스 인가 플로우를 시작하려면 device authorization 엔드포인트에 POST 요청을 보냅니다:

curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access profile'

응답에는 다음이 포함됩니다:

필드설명
device_code토큰 엔드포인트 폴링 시 앱에서 사용할 고유 코드입니다.
user_code사용자가 브라우저에 입력할 짧은 코드입니다.
verification_uri사용자가 user_code를 입력할 URL입니다.
verification_uri_completeuser_code가 미리 입력된 URL입니다. 사용자는 이 URL에 바로 접속해 수동 코드 입력을 건너뛸 수 있습니다. QR 코드, 클릭 가능한 링크 등으로 제공할 수 있습니다.
expires_indevice_codeuser_code의 유효 시간(초)입니다. 만료 후에는 폴링을 중단해야 합니다.

사용자에게 인증 URL 표시하기

디바이스 화면에 user_codeverification_uri를 표시하세요.

또는 코드가 미리 입력된 verification_uri_complete를 사용할 수도 있습니다. 사용자는 확인만 하면 됩니다. QR 코드, 클릭 가능한 링크 등 원하는 방식으로 제공할 수 있습니다.

토큰 폴링하기

사용자가 브라우저에서 인증 (Authentication)을 완료하는 동안, 디바이스는 토큰 엔드포인트를 폴링해야 합니다. 앱은 폴링 요청 사이에 최소 5초 이상 대기해야 합니다:

curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
--data-urlencode 'device_code=DEVICE_CODE'

DEVICE_CODE를 device authorization 응답에서 받은 device_code 값으로 교체하세요.

폴링을 중단해야 하는 경우:

  • 토큰 응답을 성공적으로 받은 경우
  • device code 응답의 expires_in 시간이 경과한 경우
  • expired_token 또는 access_denied와 같은 재시도 불가 오류를 받은 경우

토큰 응답

사용자가 승인을 완료하면 응답에는 다음이 포함됩니다:

필드설명
access_token액세스 토큰 (Access token). 기본적으로 불투명 토큰 (Opaque token)이며, resource를 요청하면 해당 리소스 URI가 aud로 설정된 JWT입니다.
id_token사용자 아이덴티티 클레임 (Claim)이 포함된 ID 토큰 (ID token). openid 스코프를 요청한 경우에만 제공됩니다.
refresh_token재인증 없이 새 토큰을 얻을 때 사용합니다. offline_access 스코프를 요청한 경우에만 제공됩니다.
token_type항상 Bearer입니다.
expires_in토큰의 유효 시간(초)입니다.
scope인가 서버가 부여한 스코프 (Scope)입니다.

체크포인트: 디바이스 플로우 테스트하기

이제 디바이스 플로우 연동을 테스트하세요:

  1. 앱을 실행하고 device flow를 트리거하여 device_codeuser_code를 받으세요.
  2. 브라우저에서 verification_uri를 열고 user_code를 입력하거나, verification_uri_complete로 수동 입력을 건너뛰세요.
  3. 브라우저에서 로그인 과정을 완료하세요.
  4. 앱이 폴링 후 토큰을 정상적으로 받는지 확인하세요.

사용자 정보 얻기

ID 토큰 클레임 (Claim) 디코딩하기

토큰 응답에서 반환된 id_token은 표준 JSON Web Token (JWT)입니다. Base64URL로 인코딩된 페이로드(마침표로 구분된 두 번째 부분)를 디코딩하면 추가 네트워크 요청 없이 기본 사용자 클레임 (Claim)에 접근할 수 있습니다.

디코딩된 페이로드에는 요청한 스코프 (Scope)에 따라 sub(사용자 ID), name, email 등 클레임 (Claim)이 포함됩니다.

:

운영 환경에서는 JWT 서명을 검증한 후 클레임 (Claim)을 신뢰해야 합니다. Logto 엔드포인트의 JWKS (https://your.logto.endpoint/oidc/jwks)를 사용해 토큰을 검증하세요.

userinfo 엔드포인트에서 가져오기

ID 토큰에는 요청한 스코프 (Scope)에 따라 기본 클레임 (Claim)만 포함됩니다. 일부 확장 클레임 (예: custom_data, identities)은 OIDC UserInfo 엔드포인트에서만 확인할 수 있습니다:

curl --request GET 'https://your.logto.endpoint/oidc/me' \
--header 'Authorization: Bearer ACCESS_TOKEN'

ACCESS_TOKEN을 토큰 응답에서 받은 불투명 액세스 토큰 (Opaque token) (JWT 리소스 토큰이 아님)으로 교체하세요. 응답은 부여된 스코프 (Scope)에 따라 사용자의 클레임 (Claim)이 포함된 JSON 객체입니다.

추가 클레임 (Claim) 요청하기

ID 토큰에 일부 사용자 정보가 누락된 경우가 있습니다. 이는 OAuth 2.0 및 OpenID Connect (OIDC)가 최소 권한 원칙(PoLP)을 따르도록 설계되었고, Logto도 이를 기반으로 하기 때문입니다.

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

정보:

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

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

:

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

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

추가 스코프 (Scope)를 요청하려면 device authorization 요청의 scope 파라미터에 포함하세요. 예를 들어, 사용자의 이메일과 전화번호를 요청하려면:

curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access profile email phone'

스코프 (Scope)와 클레임 (Claim)

지원되는 스코프와 해당 클레임(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_atupdated_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 리소스를 적절히 설정하는 방법을 이해하는 것을 권장합니다.

API 리소스 접근 요청하기

특정 API 리소스에 접근하려면 device authorization 요청에 resource 파라미터를 포함하세요:

curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access' \
--data-urlencode 'resource=https://your-api-resource-indicator'

사용자가 인가 (Authorization)를 완료하고 refresh token을 받으면, 해당 API 리소스용 JWT 액세스 토큰 (Access token)을 가져올 수 있습니다:

curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=REFRESH_TOKEN' \
--data-urlencode 'resource=https://your-api-resource-indicator'

응답에는 API 리소스 인디케이터가 aud로 설정된 JWT access_token이 포함됩니다.

노트:

refresh_token은 최초 device authorization 요청에 offline_access 스코프 (Scope)가 포함된 경우에만 제공됩니다. Logto는 토큰 로테이션을 사용하므로 항상 최신 refresh_token을 저장하고 사용하세요.

조직 토큰 (Organization token) 가져오기

조직이 처음이라면, 🏢 조직 (다중 테넌시)를 먼저 읽어보세요.

조직 관련 정보를 요청하려면 device authorization 요청에 urn:logto:scope:organizations 스코프 (Scope)를 추가하세요:

curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access urn:logto:scope:organizations' \
--data-urlencode 'resource=urn:logto:resource:organizations'

사용자가 로그인하면 refresh token을 사용해 조직 토큰 (Organization token)을 가져올 수 있습니다:

curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=REFRESH_TOKEN' \
--data-urlencode 'organization_id=your-organization-id'

응답에는 지정한 조직에 범위가 지정된 액세스 토큰 (Access token)이 포함됩니다.

조직 API 리소스

조직 내 API 리소스용 액세스 토큰을 가져오려면 resourceorganization_id 파라미터를 모두 포함하세요:

curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=REFRESH_TOKEN' \
--data-urlencode 'organization_id=your-organization-id' \
--data-urlencode 'resource=https://your-api-resource-indicator'

추가 자료

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