본문으로 건너뛰기

Android (Kotlin / Java) 애플리케이션에 인증 (Authentication)을 추가하세요

이 가이드는 Logto를 Android 애플리케이션에 통합하는 방법을 안내합니다.

:
  • 예제는 View 시스템View Model을 기반으로 하지만, Jetpack Compose를 사용할 때도 개념은 동일합니다.
  • 예제는 Kotlin으로 작성되었지만, 개념은 Java에서도 동일합니다.
  • KotlinJava 샘플 프로젝트는 우리의 SDK 저장소에서 사용할 수 있습니다.
  • 튜토리얼 비디오는 우리의 YouTube 채널에서 볼 수 있습니다.

사전 준비 사항

설치

노트:

Logto Android SDK가 지원하는 최소 Android API 레벨은 24입니다.

Logto Android SDK는 두 가지 주요 버전으로 제공됩니다:

  • v3: Chrome Custom Tabs (시스템 브라우저)에서 로그인 경험을 엽니다. 이를 통해 패스키 로그인과 브라우저 세션 공유가 가능합니다. v3에서는 WeChat (Native)Alipay (Native) 커넥터 지원이 제거되었습니다. 대신 WeChat (Web)Alipay (Web)을 사용할 수 있으며, 이들은 브라우저를 통해 동작합니다. 네이티브 커넥터가 필요하다면 v2를 사용하세요.
  • v2: 로그인 경험을 임베디드 WebView에서 엽니다. 이는 네이티브 소셜 커넥터에 필요하지만, 패스키 로그인을 지원하지 않습니다 (WebView는 패스키의 기반 표준인 WebAuthn을 지원하지 않음).

이 가이드는 두 버전을 모두 다룹니다. 아래 탭에서 원하는 버전을 선택하면, 선택이 가이드 전체에서 동기화됩니다.

Logto Android SDK를 설치하기 전에, Gradle 프로젝트 빌드 파일의 저장소 설정에 mavenCentral()이 추가되어 있는지 확인하세요:

settings.gradle.kts
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}

Logto Android SDK를 의존성에 추가하세요:

최신 v3 릴리스를 버전으로 사용하세요:

build.gradle.kts
dependencies {
implementation("io.logto.sdk:android:3.0.0")
}

SDK가 인터넷 접근 권한이 필요하므로, AndroidManifest.xml 파일에 다음 권한을 추가해야 합니다:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<!-- 인터넷 권한 추가 -->
<uses-permission android:name="android.permission.INTERNET" />

<!-- 기타 설정... -->
</manifest>

연동

LogtoClient 초기화

LogtoViewModel.kt 파일을 생성하고 이 뷰 모델에서 LogtoClient를 초기화하세요:

LogtoViewModel.kt
//...다른 import와 함께
import io.logto.sdk.android.LogtoClient
import io.logto.sdk.android.type.LogtoConfig

class LogtoViewModel(application: Application) : AndroidViewModel(application) {
private val logtoConfig = LogtoConfig(
endpoint = "<your-logto-endpoint>",
appId = "<your-app-id>",
scopes = null,
resources = null,
usingPersistStorage = true,
)

private val logtoClient = LogtoClient(logtoConfig, application)

companion object {
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
// extras에서 Application 객체를 가져옵니다
val application = checkNotNull(extras[APPLICATION_KEY])
return LogtoViewModel(application) as T
}
}
}
}

그런 다음, MainActivity.kt에 대한 LogtoViewModel을 생성하세요:

MainActivity.kt
//...다른 import와 함께
class MainActivity : AppCompatActivity() {
private val logtoViewModel: LogtoViewModel by viewModels { LogtoViewModel.Factory }
//...다른 코드
}

리디렉션 URI 구성

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

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

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

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

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


Logto 콘솔의 애플리케이션 세부 정보 페이지로 전환하세요. 리디렉션 URI io.logto.android://io.logto.sample/callback를 추가하고 "변경 사항 저장"을 클릭하세요.

Logto 콘솔의 리디렉션 URI

Android에서 리디렉션 URI는 다음 패턴을 따릅니다: $(LOGTO_REDIRECT_SCHEME)://$(YOUR_APP_PACKAGE)/callback:

  • LOGTO_REDIRECT_SCHEME는 reverse domain 형식의 커스텀 스킴이어야 합니다.
  • YOUR_APP_PACKAGE는 앱의 패키지 이름입니다.

예를 들어, io.logto.android를 커스텀 LOGTO_REDIRECT_SCHEME로, io.logto.sample을 앱 패키지 이름으로 사용할 경우, 리디렉션 URI는 io.logto.android://io.logto.sample/callback이 됩니다.

v3에서는 로그인 경험이 Custom Tab (시스템 브라우저)에서 열리며, 리디렉션은 OS 레벨 인텐트 필터를 통해 앱으로 전달됩니다. 앱의 빌드 파일에서 logtoRedirectScheme 매니페스트 플레이스홀더로 리디렉션 URI의 스킴을 선언해야 합니다:

build.gradle.kts
android {
defaultConfig {
manifestPlaceholders["logtoRedirectScheme"] = "io.logto.android"
}
}

또한, v3에서는 Android의 인텐트 필터 매칭을 통해 리디렉션 URI 패턴을 강제하므로, 패턴에서 벗어난 리디렉션 URI는 앱에 전달되지 않습니다:

  • 스킴은 반드시 logtoRedirectScheme 매니페스트 플레이스홀더와 같아야 합니다.
  • 호스트는 반드시 applicationId여야 합니다.
  • 경로는 반드시 /callback이어야 합니다.

스킴과 호스트는 소문자로 유지하세요. 인텐트 필터 매칭은 대소문자를 구분하며, 브라우저는 스킴을 소문자로 변환합니다.

커스텀 스킴 대신 Android App Links (https 리디렉션 URI, 소유한 도메인 사용)를 사용하려면:

  1. Digital Asset Links 파일을 https://your.domain/.well-known/assetlinks.json에 호스팅하고, 애플리케이션 ID와 서명 인증서의 SHA-256 지문을 선언하세요. Play App Signing으로 배포할 경우, Play Console의 설정 > 앱 서명에서 릴리즈 지문을 확인할 수 있습니다. 파일은 반드시 Content-Type: application/json으로 HTTP 200, 리디렉션 없이 제공되어야 합니다.

  2. SDK의 리디렉션 수신 액티비티 io.logto.sdk.android.auth.logto.LogtoRedirectReceiverActivity에 App Links 인텐트 필터를 AndroidManifest.xml에 선언하세요. 커스텀 스킴을 전혀 사용하지 않는다면, SDK의 기본 필터를 tools:node="removeAll"로 제거하고, logtoRedirectScheme 매니페스트 플레이스홀더는 더 이상 필요하지 않습니다:

    AndroidManifest.xml
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <application>
    <activity android:name="io.logto.sdk.android.auth.logto.LogtoRedirectReceiverActivity">
    <!-- 커스텀 스킴 리디렉션을 함께 사용하려면 이 줄을 생략하세요. -->
    <intent-filter tools:node="removeAll" />
    <intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="your.domain" android:path="/callback" />
    </intent-filter>
    </activity>
    </application>
    </manifest>
  3. Logto Console의 애플리케이션 상세 페이지에서 https://your.domain/callback을 리디렉션 URI (로그아웃에 사용할 경우, 로그아웃 후 리디렉션 URI)로 추가하고, signIn / signOut에 전달하세요.

이제 콜백이 실제 도메인의 URL이므로, App Links를 서버 리디렉션에서 실행하지 않는 브라우저를 위해 해당 위치에 폴백 페이지(예: "앱으로 돌아가기" 버튼)를 제공하세요. 버튼은 현재 URL로만 연결하면 됩니다(예: hrefwindow.location.href로 설정): 인가 파라미터는 쿼리 스트링에 있으며, 사용자가 클릭하면 동일한 URL이 앱으로 라우팅될 또 다른 기회를 얻게 됩니다. Android 12 이상에서는 검증되지 않은 도메인은 앱을 절대 열지 않으므로, 잘못된 assetlinks.json은 조용히 실패합니다. 검증 상태는 adb shell pm get-app-links <applicationId>로 확인할 수 있습니다.

로그인 및 로그아웃 구현

노트:

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

logtoClient.signIn을 사용하여 사용자를 로그인시키고, logtoClient.signOut을 사용하여 사용자를 로그아웃시킬 수 있습니다.

v3에서는, logtoClient.signOut이 완전한 로그아웃을 수행합니다: 로컬 자격 증명을 삭제하고, 리프레시 토큰을 폐기하며, 브라우저에서 end session endpoint를 열어 Logto 세션을 종료합니다. 이후 브라우저는 post sign-out redirect URI를 통해 다시 앱으로 이동합니다. 사용하기 전에 Logto Console의 애플리케이션 상세 페이지로 이동하여 post sign-out redirect URI io.logto.android://io.logto.sample/callback을 추가하고 "변경 사항 저장"을 클릭하세요. post sign-out redirect URI는 redirect URI와 동일한 패턴을 따르며, 스킴도 logtoRedirectScheme 매니페스트 플레이스홀더와 일치해야 합니다.

예를 들어, Android 앱에서:

LogtoModelView.kt
//...다른 import와 함께
class LogtoViewModel(application: Application) : AndroidViewModel(application) {
// ...다른 코드

// 인증 (Authentication) 상태를 관찰하기 위한 live data 추가
private val _authenticated = MutableLiveData(logtoClient.isAuthenticated)
val authenticated: LiveData<Boolean>
get() = _authenticated

fun signIn(context: Activity) {
logtoClient.signIn(context, "io.logto.android://io.logto.sample/callback") { logtoException ->
logtoException?.let { println(it) }
// live data 업데이트
_authenticated.postValue(logtoClient.isAuthenticated)
}
}

fun signOut(context: Activity) {
logtoClient.signOut(context, "io.logto.android://io.logto.sample/callback") { logtoException ->
logtoException?.let { println(it) }
// live data 업데이트
_authenticated.postValue(logtoClient.isAuthenticated)
}
}
}

그런 다음, 액티비티에서 signInsignOut 메서드를 호출하세요:

MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
//...다른 코드

// 레이아웃에 id가 "sign_in_button"인 버튼이 있다고 가정
val signInButton = findViewById<Button>(R.id.sign_in_button)
signInButton.setOnClickListener {
logtoViewModel.signIn(this)
}

// 레이아웃에 id가 "sign_out_button"인 버튼이 있다고 가정
val signOutButton = findViewById<Button>(R.id.sign_out_button)
signOutButton.setOnClickListener {
if (logtoViewModel.authenticated) { // 사용자가 인증 (Authentication)되었는지 확인
logtoViewModel.signOut(this)
}
}

// 인증 (Authentication) 상태를 관찰하여 UI 업데이트
logtoViewModel.authenticated.observe(this) { authenticated ->
if (authenticated) {
// 사용자가 인증 (Authentication)됨
signInButton.visibility = View.GONE
signOutButton.visibility = View.VISIBLE
} else {
// 사용자가 인증 (Authentication)되지 않음
signInButton.visibility = View.VISIBLE
signOutButton.visibility = View.GONE
}
}

}
}
노트:
  • post sign-out redirect URI 없이 logtoClient.signOut(context)를 호출할 수도 있습니다. 이 경우 Console 설정이 필요하지 않습니다: 브라우저에 Logto 로그아웃 페이지가 표시되고, 사용자가 수동으로 닫으면 앱으로 돌아갑니다.
  • UI 컨텍스트가 없는 경우, logtoClient.clearCredentials를 호출하여 로컬 자격 증명을 삭제하고 리프레시 토큰을 폐기할 수 있습니다. 이 경우 브라우저의 Logto 세션은 유지되므로, 다음 signIn 시 해당 세션을 통해 사용자가 자동으로 다시 로그인될 수 있습니다.

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

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

  1. 애플리케이션을 실행하면 로그인 버튼이 표시됩니다.
  2. 로그인 버튼을 클릭하면 SDK가 로그인 프로세스를 초기화하고 Logto 로그인 페이지로 리디렉션됩니다.
  3. 로그인 후, 애플리케이션으로 다시 리디렉션되어 로그아웃 버튼이 표시됩니다.
  4. 로그아웃 버튼을 클릭하여 토큰 저장소를 지우고 로그아웃합니다.

사용자 정보 가져오기

사용자 정보 표시

사용자 정보를 표시하려면 logtoClient.getIdTokenClaims() 메서드를 사용할 수 있습니다. 예를 들어, ViewModel에서 사용자 정보를 가져와 액티비티에 표시할 수 있습니다:

LogtoModelView.kt
class LogtoViewModel(application: Application) : AndroidViewModel(application) {
// ...기타 코드

// id token 클레임을 관찰할 LiveData 추가
private val _idTokenClaims = MutableLiveData<IdTokenClaims>()
val idTokenClaims: LiveData<IdTokenClaims>
get() = _idTokenClaims

fun getIdTokenClaims() {
logtoClient.getIdTokenClaims { logtoException, idTokenClaims ->
logtoException?.let { _logtoException.postValue(it) } ?: _idTokenClaims.postValue(idTokenClaims)
}
}
}
MainActivity.kt
//...다른 import와 함께
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
//...기타 코드

// 레이아웃에 id가 `user_info_text_view`인 TextView가 있다고 가정
val userInfoResponseTextView: TextView = findViewById(R.id.user_info_text_view)
logtoViewModel.userInfoResponse.observe(this) { userInfoResponse ->
userInfoResponseTextView.text = if (userInfoResponse !== null) {
val json = Gson().toJson(userInfoResponse, UserInfoResponse::class.java)
JSONObject(json).toString(2)
} else {
""
}
}
}
}

추가 클레임 요청

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

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

정보:

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

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

:

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

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

추가 스코프를 요청하려면, LogtoConfig 객체에 스코프를 전달할 수 있습니다. 예시:

LogtoViewModel.kt
private val logtoConfig = LogtoConfig(
// ...기타 설정
scopes = listOf("email", "phone"), // 또는 `listOf(UserScope.EMAIL, UserScope.PHONE)`
)

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

logtoClient.getIdTokenClaims { logtoException, idTokenClaims ->
println("IdTokenClaims:$idTokenClaims")
}
// 이제 추가 클레임 `claims.email`, `claims.phone` 등에 접근할 수 있습니다.

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

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

LogtoViewModel.kt
logtoClient.fetchUserInfo {_, userInfoResponse ->
println("UserInfoResponse:$userInfoResponse")
}
// 이제 클레임 `userInfo.custom_data`에 접근할 수 있습니다.
이 메서드는 userinfo 엔드포인트에 요청하여 사용자 정보를 가져옵니다. 사용 가능한 스코프와 클레임에 대해 더 알고 싶다면, 스코프와 클레임 섹션을 참조하세요.

스코프와 클레임

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

표준 OIDC 클레임 (Claim)의 경우, ID 토큰에 포함되는지는 요청된 스코프 (Scope)에 의해 엄격하게 결정됩니다. 확장 클레임 (예: custom_dataorganizations)은 커스텀 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_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 리소스를 적절히 설정하는 방법을 이해하는 것을 권장합니다.

Logto 클라이언트 구성

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

LogtoViewModel.kt
val logtoConfig = LogtoConfig(
//...other configs
resources = listOf("https://shopping.your-app.com/api", "https://store.your-app.com/api"), // API 리소스를 추가하세요
)

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

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

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

LogtoViewModel.kt
val logtoConfig = LogtoConfig(
// ..other configs
scopes = listOf("shopping:read", "shopping:write", "store:read", "store:write"),
resources = listOf("https://shopping.your-app.com/api", "https://store.your-app.com/api"),
)

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

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

LogtoViewModel.kt
val logtoConfig = LogtoConfig(
// ...other configs
scopes = listOf("read", "write"),
resources = listOf("https://shopping.your-app.com/api", "https://store.your-app.com/api"),
)

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

노트:

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

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

API 리소스용 액세스 토큰 가져오기

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

LogtoViewModel.kt
logtoClient.getAccessToken("https://shopping.your-app.com/api") { logtoException, accessToken ->
logtoException?.let { println(it) }
accessToken?.let { println(it) }
}

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

조직 토큰 가져오기

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

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

LogtoViewModel.kt
val logtoConfig = LogtoConfig(
// ...other configs
scopes = listOf(UserScope.Organizations),
)

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

LogtoViewModel.kt
// 매개변수를 유효한 조직 ID로 교체하세요.
// 사용자를 위한 유효한 조직 ID는 ID 토큰 클레임 `organizations`에서 찾을 수 있습니다.
logtoClient.getOrganizationToken("organization-id") { logtoException, organizationToken ->
logtoException?.let { println(it) }
organizationToken?.let { println(it) }
}

// 또는
logtoClient.getOrganizationTokenClaims("organization-id") { logtoException, claims ->
logtoException?.let { println(it) }
claims?.let { println(it) }
}

조직 API 리소스

조직 내 API 리소스에 대한 액세스 토큰을 가져오기 위해, getAccessToken 메서드를 API 리소스와 조직 ID를 매개변수로 사용하여 호출할 수 있습니다:

LogtoViewModel.kt
logtoClient.getAccessToken(
'https://shopping.your-app.com/api',
organizationId
) { logtoException, accessToken ->
println("AccessToken:$accessToken")
}

추가 자료

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