웨어러블 기기에서 인증: 인증 관리자

Wear OS 앱은 호환 앱 없이도 독립형으로 실행할 수 있습니다. 따라서 Wear OS 앱은 인터넷에서 데이터에 액세스할 때 자체적으로 인증을 관리해야 합니다. 시계의 작은 화면 크기와 줄어든 입력 기능으로 Wear OS 앱에서 사용할 수 있는 인증 옵션이 제한됩니다.

이 가이드에서는 Wear OS 앱에 권장되는 인증 방법인 인증 관리자에 관한 안내를 제공합니다.

좋은 로그인 환경을 설계하는 방법을 자세히 알아보려면 로그인 UX 가이드를 참고하세요.

사전 고려사항

구현을 시작하기 전에 다음 사항을 고려하세요.

게스트 모드

모든 기능에 대해 인증을 요구해서는 안 됩니다. 대신 사용자가 로그인하지 않고도 최대한 많은 기능을 제공하세요.

사용자는 모바일 앱을 사용하지 않고도 Wear 앱을 찾아 설치할 수 있으므로 계정이 없거나 제공되는 기능을 모를 수 있습니다. 게스트 모드 기능이 앱의 기능을 정확하게 보여줘야 합니다.

일부 기기의 잠금이 더 오래 유지될 수 있음

Wear OS 5 이상을 실행하는 지원 기기에서 시스템은 사용자가 기기를 손목에 착용하고 있는지 감지합니다. 사용자가 손목 감지를 사용 중지한 후 손목에서 기기를 벗으면 시스템은 평소보다 더 오랫동안 기기의 잠금을 해제된 상태로 유지합니다.

앱에 더 높은 수준의 보안이 필요한 경우(예: 민감하거나 비공개 데이터가 표시되는 경우) 먼저 손목 감지가 사용 설정되어 있는지 확인합니다.

fun isWristDetectionAutoLockingEnabled(context: Context): Boolean {
    // Use the keyguard manager to check for the presence of a lock mechanism
    val keyguardManager = context.getSystemService<KeyguardManager>()
    val isSecured = keyguardManager?.isDeviceSecure == true

    // Use OEM-specific system settings to verify that on-body autolock is enabled.
    val isWristDetectionOn = android.provider.Settings.Global.getInt(
        context.contentResolver, PIXEL_WRIST_AUTOLOCK_SETTING_STATE,
        0
    ) == 1

    return isSecured && isWristDetectionOn
}

이 메서드의 반환 값이 false이면 사용자별 콘텐츠를 표시하기 전에 사용자에게 앱에서 계정에 로그인하라는 메시지를 표시합니다.

인증 관리자

인증 관리자는 Wear OS에서 인증을 위한 권장 API입니다. 연결된 페어링된 휴대전화가 필요하지 않고 비밀번호를 기억할 필요 없이 독립형 설정에서 사용자가 Wear OS 애플리케이션에 로그인할 수 있는 더 안전한 환경을 제공합니다.

이 문서에서는 개발자가 호스팅하는 표준 인증 메커니즘을 사용하여 인증 관리자 솔루션을 구현하는 데 필요한 정보를 간략하게 설명합니다. 표준 인증 메커니즘은 다음과 같습니다.

  • 패스키
  • 비밀번호
  • 제휴 ID (예: Google 계정으로 로그인)

이 가이드에서는 인증 관리자의 백업으로 허용되는 다른 Wear OS 인증 방법 (데이터 영역 토큰 공유OAuth)을 이전하는 방법과 이제 지원 중단된 독립형 Google 계정으로 로그인 버튼 에서 삽입된 인증 관리자 버전으로 전환하는 특별한 방법 을 안내합니다.

Wear OS 제한사항 및 차이점

개발자는 Wear OS의 다음 제한사항과 차이점을 염두에 두어야 합니다.

  • 인증 관리자는 Wear OS 3 이상에서 사용할 수 있습니다.
  • Wear OS에서는 사용자 인증 정보를 만들 수 없습니다.
  • 사용자 인증 정보 복원 또는 하이브리드 로그인 흐름은 지원되지 않습니다.
  • Wear OS 통합이 있는 인증 제공업체만 모바일에서 재사용할 수 있습니다.

Wear OS의 패스키

개발자는 Wear OS 인증 관리자 구현에서 패스키를 구현하는 것이 좋습니다. 패스키는 최종 사용자 인증을 위한 새로운 업계 표준이며 사용자에게 여러 가지 중요한 이점을 제공합니다.

패스키는 더 쉽습니다.

  • 사용자는 로그인할 계정을 선택할 수 있습니다. 사용자 이름을 입력할 필요가 없습니다.
  • 사용자는 기기의 화면 잠금을 사용하여 인증할 수 있습니다.
  • 패스키가 생성되고 등록되면 사용자는 새 기기로 원활하게 전환하고 다시 등록할 필요 없이 즉시 사용할 수 있습니다.

패스키는 더 안전합니다.

  • 개발자는 비밀번호를 저장하는 대신 공개 키만 서버에 저장합니다. 즉, 악의적인 사용자가 서버를 해킹할 가치가 훨씬 적고 침해 발생 시 정리해야 할 작업이 훨씬 적습니다.
  • 패스키는 피싱 방지 보호를 제공합니다. 패스키는 등록된 웹사이트와 앱에서만 작동합니다. 브라우저 또는 OS에서 인증을 처리하므로 사용자가 기만적인 사이트에서 인증하도록 속일 수 없습니다.
  • 패스키는 SMS 전송의 필요성을 줄여 인증을 더 비용 효율적으로 만듭니다.

패스키 구현

모든 구현 유형의 설정 및 안내가 포함되어 있습니다.

설정

  1. 애플리케이션 모듈의 build.gradle 파일에서 대상 API 수준을 35로 설정합니다.

    android {
        defaultConfig {
            targetSdk(35)
        }
    }
    
  2. 앱 또는 모듈의 build.gradle 파일에 다음 줄을 추가합니다. androidx.credentials 출시 참조의 최신 안정화 버전을 사용합니다.

    androidx.credentials:credentials:1.6.0
    androidx.credentials:credentials-play-services-auth:1.6.0
    

기본 제공되는 인증 방법

인증 관리자는 통합 API이므로 Wear OS의 구현 단계는 다른 기기 유형과 동일합니다.

모바일 안내 에 따라 시작하고 패스키 및 비밀번호 지원을 구현하세요.

인증 관리자에 Google 계정으로 로그인 지원을 추가하는 단계는 모바일 개발을 위한 것이지만 Wear OS에서도 단계는 동일합니다.

Wear OS에서는 사용자 인증 정보를 만들 수 없으므로 모바일 안내에 언급된 사용자 인증 정보 생성 메서드를 구현할 필요가 없습니다.

백업 인증 방법

Wear OS 앱에 허용되는 다른 두 가지 인증 방법은 OAuth 2.0 (두 가지 변형 중 하나)과 모바일 인증 토큰 데이터 영역 공유입니다. 이러한 방법은 인증 관리자 API에 통합 지점이 없지만 사용자가 인증 관리자 화면을 닫는 경우 인증 관리자의 UX 흐름에 대체로 포함될 수 있습니다.

인증 관리자 화면을 닫는 사용자 작업을 처리하려면 NoCredentialException 로직의 일부로 GetCredential 을 포착하고 자체 맞춤 인증 UI로 이동합니다.

try {
    val getCredentialResponse: GetCredentialResponse =
        credentialManager.getCredential(activity, createGetCredentialRequest())
    return authenticate(getCredentialResponse.credential)
} catch (_: GetCredentialCancellationException) {
    navigateToSecondaryAuthentication()
}

그러면 맞춤 인증 UI는 로그인 UX 가이드에 설명된 다른 허용되는 인증 방법 을 제공할 수 있습니다.

데이터 영역 토큰 공유

휴대전화의 호환 앱은 웨어러블 데이터 영역 API를 통해 인증 데이터를 Wear OS 앱에 안전하게 전송할 수 있습니다. 사용자 인증 정보를 메시지 또는 데이터 항목으로 전송합니다.

이러한 유형의 인증은 일반적으로 사용자의 작업 없이도 가능합니다. 그러나 사용자에게 로그인 중임을 알리지 않고 인증을 실행해서는 안 됩니다. 닫을 수 있는 화면을 통해 계정이 모바일에서 전송 중임을 사용자에게 알릴 수 있습니다.

중요: 이 옵션은 모바일 앱이 설치된 경우에만 Android와 페어링된 시계에서 작동하므로 Wear OS 앱은 다른 인증 방법을 하나 이상 제공해야 합니다. 모바일 앱이 없거나 Wear OS 기기가 iOS 기기와 페어링된 사용자를 위해 대체 인증 방법을 제공하세요.

다음 예와 같이 모바일 앱의 데이터 영역을 사용하여 토큰을 전달합니다.

val token = "..." // Auth token to transmit to the Wear OS device.
val putDataReq: PutDataRequest = PutDataMapRequest.create("/auth").run {
    dataMap.putString("token", token)
    asPutDataRequest()
}
val putDataTask: Task<DataItem> = Wearable.getDataClient(this).putDataItem(putDataReq)

다음 예와 같이 Wear OS 앱에서 데이터 변경 이벤트를 수신 대기합니다.

class AuthDataListenerService : WearableListenerService() {
    override fun onDataChanged(dataEvents: DataEventBuffer) {
        dataEvents.forEach { event ->
            if (event.type == DataEvent.TYPE_CHANGED) {
                val dataItemPath = event.dataItem.uri.path ?: ""

                if (dataItemPath.startsWith("/auth")) {
                    val token = DataMapItem.fromDataItem(event.dataItem)
                        .dataMap
                        .getString("token")
                    // Display an interstitial screen to notify the user that they're being signed
                    // in. Then, store the token and use it in network requests.
                    handleSignInSequence(token)
                }
            }
        }
    }

    /** placeholder sign in handler. */
    fun handleSignInSequence(token: String?) {}
}

웨어러블 데이터 영역 사용에 관한 자세한 내용은 Wear OS에서 데이터 보내기 및 동기화를 참고하세요.

OAuth 2.0 사용

Wear OS는 다음 섹션에 설명된 두 가지 OAuth 2.0 기반 흐름을 지원합니다.

PKCE (Proof Key for Code Exchange)

PKCE를 효과적으로 사용하려면 RemoteAuthClient를 사용하세요. 그런 다음 Wear OS 앱에서 OAuth 제공자에 인증 요청을 실행하려면 OAuthRequest 객체를 만듭니다. 이 객체는 `CodeChallenge` 객체와 토큰을 가져오기 위한 OAuth 엔드포인트 URL로 구성됩니다. CodeChallenge

다음 코드는 인증 요청을 만드는 예를 보여줍니다.

val oauthRequest = OAuthRequest.Builder(context)
    .setAuthProviderUrl(uri)
    .setCodeChallenge(codeChallenge)
    .setClientId(CLIENT_ID)
    .build()

인증 요청을 빌드한 후 sendAuthorizationRequest() 메서드를 사용하여 호환 앱으로 보냅니다.

RemoteAuthClient.create(context).sendAuthorizationRequest(
    request = oauthRequest,
    executor = { command -> command?.run() },
    clientCallback = object : RemoteAuthClient.Callback() {
        override fun onAuthorizationResponse(
            request: OAuthRequest,
            response: OAuthResponse
        ) {
            // Extract the token from the response, store it, and use it in requests.
            continuation.resume(parseCodeFromResponse(response))
        }
        override fun onAuthorizationError(request: OAuthRequest, errorCode: Int) {
            // Handle Errors
            continuation.resume(Result.failure(IOException("Authorization failed")))
        }
    }
)

이 요청은 호환 앱에 호출을 트리거하고, 이렇게 하면 사용자 휴대전화의 웹브라우저에 승인 UI가 표시됩니다. OAuth 2.0 제공자가 사용자를 인증하고 요청된 권한에 관한 사용자 동의를 얻습니다. 응답은 자동으로 생성된 리디렉션 URL로 전송됩니다.

승인이 성공 또는 실패한 후 OAuth 2.0 서버가 요청에 지정된 URL로 리디렉션됩니다. 사용자가 액세스 요청을 승인하면 응답에 승인 코드가 포함됩니다. 사용자가 요청을 승인하지 않으면 응답에 오류 메시지가 포함됩니다.

응답은 쿼리 문자열 형식이며 다음 예 중 하나와 유사합니다.

  https://wear.googleapis.com/3p_auth/com.your.package.name?code=xyz
  https://wear.googleapis-cn.com/3p_auth/com.your.package.name?code=xyz

이렇게 하면 사용자를 호환 앱으로 연결하는 페이지가 로드됩니다. 호환 앱은 응답 URL을 확인하고 onAuthorizationResponse API를 사용하여 Wear OS 앱에 응답을 전달합니다.

그러면 시계 앱은 승인 코드를 액세스 토큰으로 교환할 수 있습니다.

기기 승인 부여

기기 승인 부여를 사용하면 사용자는 다른 기기에서 인증 URI를 열게 됩니다. 그러면 승인 서버는 사용자에게 요청을 승인하거나 거부하도록 요청합니다.

이 과정을 더 쉽게 하려면 RemoteActivityHelper를 사용하여 페어링된 사용자의 휴대기기에서 웹페이지를 엽니다. 다음 예에서와 같습니다.

// Request access from the authorization server and receive Device Authorization Response.
private fun verifyDeviceAuthGrant(verificationUri: String) {
    RemoteActivityHelper(context).startRemoteActivity(
        Intent(Intent.ACTION_VIEW).apply {
            addCategory(Intent.CATEGORY_BROWSABLE)
            data = Uri.parse(verificationUri)
        },
        null
    )
}

iOS 앱을 사용하는 경우 범용 링크를 사용하여 브라우저에서 토큰을 승인하는 방법 대신 앱에서 이 인텐트를 가로챕니다.