あなたの Android (Kotlin/Java) アプリケーションに認証 (Authentication) を追加する
このガイドでは、Logto をあなたの Android アプリケーションに統合する方法を示します。
- この例は View システム と View Model に基づいていますが、Jetpack Compose を使用する場合でも概念は同じです。
- この例は Kotlin で書かれていますが、Java でも概念は同じです。
- Kotlin と Java のサンプルプロジェクトは、私たちの SDK リポジトリ で利用可能です。
- チュートリアルビデオは、私たちの YouTube チャンネル で視聴できます。
前提条件
- Logto Cloud アカウントまたは セルフホスト Logto。
- 作成された Logto ネイティブアプリケーション。
- Kotlin Android アプリケーションプロジェクト。
インストール
Logto Android SDK のサポートされている最小 Android API レベルはレベル 24 です。
Logto Android SDK には 2 つのメジャーバージョンがあります:
- v2:埋め込み WebView でサインインエクスペリエンスを開きます。ネイティブソーシャルコネクターに必要ですが、パスキーサインインをサポートしていません(WebView はパスキーの基礎となる標準である WebAuthn をサポートしていません)。
- v3 (beta):Chrome Custom Tabs(システムブラウザ)でサインインエクスペリエンスを開き、パスキーサインインが可能になり、ブラウザセッションを共有します。v3 は WeChat (Native) および Alipay (Native) コネクターのサポートを削除します。代わりに、ブラウザを通じて動作する WeChat (Web) および Alipay (Web) を使用できます。ネイティブコネクターに依存している場合は、v2 のままにしてください。
このガイドでは両方のバージョンを説明します。以下のタブでバージョンを選択すると、選択がこのガイド全体で同期されます。
Logto Android SDK をインストールする前に、Gradle プロジェクトのビルドファイルで mavenCentral() がリポジトリ設定に追加されていることを確認してください:
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}
Logto Android SDK を依存関係に追加します:
- v2
- v3 (beta)
- Kotlin
- Groovy
dependencies {
implementation("io.logto.sdk:android:2.0.3")
}
dependencies {
implementation 'io.logto.sdk:android:2.0.3'
}
v3 は GA まで 3.0.0-beta プレリリースとしてリリースされています。最新のプレリリースをバージョンとして使用してください:
- Kotlin
- Groovy
dependencies {
implementation("io.logto.sdk:android:3.0.0-beta")
}
dependencies {
implementation 'io.logto.sdk:android:3.0.0-beta'
}
SDK はインターネットアクセスが必要なため、次の権限を 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 を初期化します:
//...他のインポート
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 を作成します:
//...他のインポート
class MainActivity : AppCompatActivity() {
private val logtoViewModel: LogtoViewModel by viewModels { LogtoViewModel.Factory }
//...他のコード
}
リダイレクト URI の設定
詳細に入る前に、エンドユーザー体験の概要を簡単にご紹介します。サインインプロセスは次のようにシンプルにまとめられます:
- アプリがサインインメソッドを呼び出します。
- ユーザーは Logto のサインインページにリダイレクトされます。ネイティブアプリの場合は、システムブラウザが開かれます。
- ユーザーがサインインし、アプリ(リダイレクト URI として設定)に戻されます。
リダイレクトベースのサインインについて
- この認証 (Authentication) プロセスは OpenID Connect (OIDC) プロトコルに従い、Logto はユーザーのサインインを保護するために厳格なセキュリティ対策を講じています。
- 複数のアプリがある場合、同じアイデンティティプロバイダー (Logto) を使用できます。ユーザーがあるアプリにサインインすると、Logto は別のアプリにアクセスした際に自動的にサインインプロセスを完了します。
リダイレクトベースのサインインの理論と利点について詳しく知るには、Logto サインイン体験の説明を参照してください。
Logto コンソールのアプリケーション詳細ページに切り替えましょう。リダイレクト URI io.logto.android://io.logto.sample/callback を追加し、「変更を保存」をクリックします。
Android では、リダイレクト URI は次のパターンに従います:$(LOGTO_REDIRECT_SCHEME)://$(YOUR_APP_PACKAGE)/callback:
LOGTO_REDIRECT_SCHEMEは逆ドメイン形式のカスタムスキームである必要があります。YOUR_APP_PACKAGEはあなたのアプリのパッケージ名です。
io.logto.android をカスタム LOGTO_REDIRECT_SCHEME とし、io.logto.sample をあなたのアプリのパッケージ名と仮定すると、リダイレクト URI は io.logto.android://io.logto.sample/callback になります。
- v2
- v3 (beta)
追加の設定は不要です。サインインエクスペリエンスは埋め込み WebView で開き、SDK は WebView 内でリダイレクトをインターセプトします。
v3 では、サインインエクスペリエンスは Custom Tab(システムブラウザ)で開き、リダイレクトは OS レベルのインテントフィルターを通じてアプリに戻されます。アプリのビルドファイルで logtoRedirectScheme マニフェストプレースホルダーを使用してリダイレクト URI のスキームを宣言する必要があります:
- Kotlin
- Groovy
android {
defaultConfig {
manifestPlaceholders["logtoRedirectScheme"] = "io.logto.android"
}
}
android {
defaultConfig {
manifestPlaceholders.logtoRedirectScheme = 'io.logto.android'
}
}
さらに、v3 は Android のインテントフィルターマッチングを通じてリダイレクト URI パターンを強制するため、パターンから外れたリダイレクト URI はアプリに届きません:
- スキームは
logtoRedirectSchemeマニフェストプレースホルダーと等しくなければなりません。 - ホストは
applicationIdでなければなりません。 - パスは
/callbackでなければなりません。
インテントフィルターマッチングは大文字と小文字を区別し、ブラウザはスキームを小文字にするため、スキームとホストは小文字に保ってください。
カスタムスキームの代わりに App Links を使用しますか?
Android App Links(所有するドメインの https リダイレクト URI)をカスタムスキームの代わりに使用するには:
-
Digital Asset Links ファイルを
https://your.domain/.well-known/assetlinks.jsonにホストし、アプリケーション ID と署名証明書の SHA-256 フィンガープリントを宣言します。Play アプリ署名で公開する場合は、Play Console の 設定 > アプリ署名 でリリースフィンガープリントを確認できます。ファイルはContent-Type: application/jsonとして HTTP 200 で、リダイレクトなしで提供される必要があります。 -
SDK のリダイレクトレシーバーアクティビティ
io.logto.sdk.android.auth.logto.LogtoRedirectReceiverActivityの App Links インテントフィルターをAndroidManifest.xmlファイルで宣言します。カスタムスキームをまったく使用しない場合は、tools:node="removeAll"で SDK の組み込みフィルターを削除してください。その場合、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> -
Logto Console のアプリケーション詳細ページで
https://your.domain/callbackをリダイレクト URI として(サインアウトにも使用する場合はサインアウト後のリダイレクト URI としても)追加し、signIn/signOutに渡します。
コールバックはドメイン上の実際の URL になったことに注意してください。サーバーリダイレクトで App Links を起動しないブラウザのために、フォールバックページ(例:「アプリに戻る」ボタン)を提供してください。ボタンは現在の URL にリンクするだけで十分です(例:href を window.location.href に設定)。認可パラメーターはクエリ文字列にあり、ユーザーによるクリックで同じ URL がアプリにルーティングされる機会が再び得られます。Android 12 以降では、未確認のドメインはアプリを開かないため、壊れた assetlinks.json はサイレントに失敗します。adb shell pm get-app-links <applicationId> で確認状態を確認できます。
サインインとサインアウトの実装
logtoClient.signIn を呼び出す前に、Admin Console でリダイレクト URI
が正しく設定されていることを確認してください。 :::
logtoClient.signIn を使用してユーザーをサインインし、logtoClient.signOut を使用してユーザーをサインアウトできます。
- v2
- v3 (beta)
例えば、Android アプリでは次のようにします:
//...他のインポートと共に
class LogtoViewModel(application: Application) : AndroidViewModel(application) {
// ...他のコード
// 認証 (Authentication) 状態を監視するライブデータを追加
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) }
// ライブデータを更新
_authenticated.postValue(logtoClient.isAuthenticated)
}
}
fun signOut() {
logtoClient.signOut { logtoException ->
logtoException?.let { println(it) }
// ライブデータを更新
_authenticated.postValue(logtoClient.isAuthenticated)
}
}
}
次に、アクティビティ内で signIn と signOut メソッドを呼び出します:
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()
}
}
// 認証 (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
}
}
}
}
v3 では、logtoClient.signOut は完全なサインアウトを実行します。ローカルの資格情報をクリアし、リフレッシュトークンを失効させ、ブラウザでエンドセッションエンドポイントを開いて Logto セッションを終了します。その後、ブラウザはサインアウト後のリダイレクト URI を通じてアプリに戻ります。使用する前に、Logto Console のアプリケーション詳細ページに切り替え、サインアウト後のリダイレクト URI io.logto.android://io.logto.sample/callback を追加して「変更を保存」をクリックしてください。サインアウト後のリダイレクト URI はリダイレクト URI と同じパターンに従い、そのスキームも logtoRedirectScheme マニフェストプレースホルダーと一致する必要があります。
例えば、Android アプリでは次のようにします:
//...他のインポートと共に
class LogtoViewModel(application: Application) : AndroidViewModel(application) {
// ...他のコード
// 認証 (Authentication) 状態を監視するライブデータを追加
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) }
// ライブデータを更新
_authenticated.postValue(logtoClient.isAuthenticated)
}
}
fun signOut(context: Activity) {
logtoClient.signOut(context, "io.logto.android://io.logto.sample/callback") { logtoException ->
logtoException?.let { println(it) }
// ライブデータを更新
_authenticated.postValue(logtoClient.isAuthenticated)
}
}
}
次に、アクティビティ内で signIn と signOut メソッドを呼び出します:
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
}
}
}
}
- サインアウト後のリダイレクト URI なしで
logtoClient.signOut(context)を呼び出すこともできます。この場合、Console の設定は不要です。ブラウザが Logto のサインアウトページを表示し、ユーザーは手動で閉じてアプリに戻ります。 - UI コンテキストが利用できない場合は、
logtoClient.clearCredentialsを呼び出してローカルの資格情報をクリアし、リフレッシュトークンを失効させることができます。ただし、これはブラウザの Logto セッションをそのままにするため、次のsignInでそのセッションを通じてサイレントにサインインされる可能性があります。
チェックポイント: アプリケーションをテストする
これで、アプリケーションをテストできます:
- アプリケーションを実行すると、サインインボタンが表示されます。
- サインインボタンをクリックすると、SDK がサインインプロセスを初期化し、Logto のサインインページにリダイレクトされます。
- サインインすると、アプリケーションに戻り、サインアウトボタンが表示されます。
- サインアウトボタンをクリックして、トークンストレージをクリアし、サインアウトします。
ユーザー情報の取得
ユーザー情報の表示
ユーザーの情報を表示するには、logtoClient.getIdTokenClaims() メソッドを使用できます。例えば、ViewModel でユーザー情報を取得し、それをアクティビティで表示することができます:
class LogtoViewModel(application: Application) : AndroidViewModel(application) {
// ...他のコード
// ID トークンクレームを監視するライブデータを追加
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)
}
}
}
//...他のインポートと共に
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
//...他のコード
// レイアウトに `user_info_text_view` という ID のテキストビューがあると仮定
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
はこれらの標準に基づいて構築されているためです。
デフォルトでは、限られたクレーム (Claims) が返されます。より多くの情報が必要な場合は、追加のスコープ (Scopes) をリクエストして、より多くのクレーム (Claims) にアクセスできます。
「クレーム (Claim)」はサブジェクトについての主張であり、「スコープ (Scope)」はクレーム (Claims) のグループです。現在のケースでは、クレーム (Claim) はユーザーに関する情報の一部です。
スコープ (Scope) とクレーム (Claim) の関係の非規範的な例を示します:
「sub」クレーム (Claim) は「サブジェクト (Subject)」を意味し、ユーザーの一意の識別子(つまり、ユーザー ID)です。
Logto SDK は常に 3 つのスコープ (Scopes) をリクエストします:openid、profile、および offline_access。
追加のスコープをリクエストするには、スコープを LogtoConfig オブジェクトに渡すことができます。例えば:
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` などにアクセスできます。
ネットワークリクエストが必要なクレーム (Claims)
ID トークンの肥大化を防ぐために、一部のクレーム (Claims) は取得するためにネットワークリクエストが必要です。例えば、custom_data クレームはスコープで要求されてもユーザーオブジェクトに含まれません。これらのクレームにアクセスするには、 logtoClient.fetchUserInfo() メソッドを使用できます:
logtoClient.fetchUserInfo {_, userInfoResponse ->
println("UserInfoResponse:$userInfoResponse")
}
// これでクレーム `userInfo.custom_data` にアクセスできます。
スコープとクレーム
Logto は OIDC の スコープ (Scope) とクレーム (Claim) の規約 を使用して、ID トークンおよび OIDC userinfo エンドポイント からユーザー情報を取得するためのスコープ (Scope) とクレーム (Claim) を定義しています。「スコープ (Scope)」と「クレーム (Claim)」は、OAuth 2.0 および OpenID Connect (OIDC) 仕様の用語です。
標準の OIDC クレーム (Claim) については、ID トークンへの含有はリクエストされたスコープ (Scope) によって厳密に決定されます。拡張クレーム (Claim)(例:custom_data や organizations)は、カスタム ID トークン 設定を通じて ID トークンに追加で表示するように構成できます。
こちらはサポートされているスコープと対応するクレーム (Claims) の一覧です:
標準 OIDC スコープ
openid(デフォルト)
| Claim name | Type | 説明 |
|---|---|---|
| sub | string | ユーザーの一意の識別子 |
profile(デフォルト)
| Claim name | Type | 説明 |
|---|---|---|
| name | string | ユーザーのフルネーム |
| username | string | ユーザー名 |
| picture | string | エンドユーザーのプロフィール画像の URL。この URL は画像ファイル(例:PNG、JPEG、GIF 画像ファイル)を指す必要があり、画像を含む Web ページではありません。この URL は、エンドユーザーを説明する際に表示するのに適したプロフィール写真を特に参照するべきであり、エンドユーザーが撮影した任意の写真ではありません。 |
| created_at | number | エンドユーザーが作成された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。 |
| updated_at | number | エンドユーザー情報が最後に更新された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。 |
その他の 標準クレーム (Standard Claims) には、family_name、given_name、middle_name、nickname、preferred_username、profile、website、gender、birthdate、zoneinfo、locale などがあり、これらも profile スコープに含まれます(userinfo エンドポイントをリクエストする必要はありません)。上記のクレームとの違いは、これらのクレームは値が空でない場合のみ返される点です。一方、上記のクレームは値が空の場合 null が返されます。
標準クレーム (Standard Claims) とは異なり、created_at および updated_at クレームは秒ではなくミリ秒を使用しています。
email
| Claim name | Type | 説明 |
|---|---|---|
string | ユーザーのメールアドレス | |
| email_verified | boolean | メールアドレスが認証済みかどうか |
phone
| Claim name | Type | 説明 |
|---|---|---|
| phone_number | string | ユーザーの電話番号 |
| phone_number_verified | boolean | 電話番号が認証済みかどうか |
address
アドレスクレームの詳細については OpenID Connect Core 1.0 を参照してください。
(デフォルト) と記載されたスコープは常に Logto SDK によってリクエストされます。標準 OIDC スコープ下のクレーム (Claims) は、対応するスコープがリクエストされた場合、常に ID トークン (ID token) に含まれます — 無効化できません。
拡張スコープ
以下のスコープは Logto によって拡張されており、userinfo エンドポイント を通じてクレーム (Claims) を返します。これらのクレームは Console > Custom JWT を通じて ID トークン (ID token) に直接含めるよう設定することもできます。詳細は カスタム ID トークン を参照してください。
custom_data
| Claim name | Type | 説明 | デフォルトで ID トークンに含まれるか |
|---|---|---|---|
| custom_data | object | ユーザーのカスタムデータ |
identities
| Claim name | Type | 説明 | デフォルトで ID トークンに含まれるか |
|---|---|---|---|
| identities | object | ユーザーのリンク済みアイデンティティ | |
| sso_identities | array | ユーザーのリンク済み SSO アイデンティティ |
roles
| Claim name | Type | 説明 | デフォルトで ID トークンに含まれるか |
|---|---|---|---|
| roles | string[] | ユーザーのロール | ✅ |
urn:logto:scope:organizations
| Claim name | Type | 説明 | デフォルトで ID トークンに含まれるか |
|---|---|---|---|
| organizations | string[] | ユーザーが所属する組織 ID | ✅ |
| organization_data | object[] | ユーザーが所属する組織データ |
これらの組織クレーム (Organization Claims) は、不透明トークン (Opaque token) を使用している場合でも userinfo エンドポイント経由で取得できます。ただし、不透明トークン (Opaque token) は組織トークン (Organization token) として組織固有リソースへのアクセスには使用できません。詳細は 不透明トークン (Opaque token) と組織 (Organizations) を参照してください。
urn:logto:scope:organization_roles
| Claim name | Type | 説明 | デフォルトで ID トークンに含まれるか |
|---|---|---|---|
| organization_roles | string[] | ユーザーが所属する組織ロール(<organization_id>:<role_name> 形式) | ✅ |
API リソースと組織
まず 🔐 ロールベースのアクセス制御 (RBAC) を読むことをお勧めします。これにより、Logto の RBAC の基本概念と API リソースを適切に設定する方法を理解できます。
Logto クライアントの設定
API リソースを設定したら、アプリで Logto を設定する際にそれらを追加できます:
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:read と shopping:write の権限があり、https://store.your-app.com/api リソースには store:read と store:write の権限があります。
これらの権限を要求するには、アプリで Logto を設定する際にそれらを追加できます:
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 リソースは、プレフィックスなしで read と write スコープを持つことができます。その後、Logto の設定では:
val logtoConfig = LogtoConfig(
// ...other configs
scopes = listOf("read", "write"),
resources = listOf("https://shopping.your-app.com/api", "https://store.your-app.com/api"),
)
各 API リソースは、read と write の両方のスコープを要求します。
API リソースで定義されていないスコープを要求しても問題ありません。例えば、API リソースに email スコープが利用できなくても、email スコープを要求できます。利用できないスコープは安全に無視されます。
サインインが成功すると、Logto はユーザーのロールに応じて適切なスコープを API リソースに発行します。
API リソースのためのアクセス トークンの取得
特定の API リソースのアクセス トークンを取得するには、getAccessToken メソッドを使用できます:
logtoClient.getAccessToken("https://shopping.your-app.com/api") { logtoException, accessToken ->
logtoException?.let { println(it) }
accessToken?.let { println(it) }
}
このメソッドは、ユーザーが関連する権限を持っている場合に API リソースにアクセスするために使用できる JWT アクセス トークンを返します。現在キャッシュされているアクセス トークンが期限切れの場合、このメソッドは自動的にリフレッシュ トークンを使用して新しいアクセス トークンを取得しようとします。
組織トークンの取得
組織 (Organization) が初めての場合は、🏢 組織 (マルチテナンシー) を読んで始めてください。
Logto クライアントを設定する際に、UserScope.Organizations スコープを追加する必要があります:
val logtoConfig = LogtoConfig(
// ...other configs
scopes = listOf(UserScope.Organizations),
)
ユーザーがサインインしたら、ユーザーのための組織トークンを取得できます:
// パラメーターを有効な組織 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 の両方をパラメーターとして渡すことができます:
logtoClient.getAccessToken(
'https://shopping.your-app.com/api',
organizationId
) { logtoException, accessToken ->
println("AccessToken:$accessToken")
}