1+ /*
2+ * Copyright 2025 The Android Open Source Project
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * https://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+
18+ package com.example.identity.credentialmanager
19+
20+ import android.content.Context
21+ import android.os.Build
22+ import android.os.Bundle
23+ import android.util.Log
24+ import androidx.annotation.RequiresApi
25+ import androidx.credentials.CredentialManager
26+ import androidx.credentials.CustomCredential
27+ import androidx.credentials.GetCredentialRequest
28+ import androidx.credentials.GetCredentialResponse
29+ import androidx.credentials.GetPasswordOption
30+ import androidx.credentials.GetPublicKeyCredentialOption
31+ import androidx.credentials.PasswordCredential
32+ import androidx.credentials.PublicKeyCredential
33+ import androidx.credentials.exceptions.GetCredentialException
34+ import kotlinx.coroutines.coroutineScope
35+ import kotlinx.coroutines.runBlocking
36+ import org.json.JSONObject
37+
38+ class CredentialManagerFunctions (
39+ context : Context ,
40+ ) {
41+ // [START android_identity_initialize_credman]
42+ // Use your app or activity context to instantiate a client instance of
43+ // CredentialManager.
44+ private val credentialManager = CredentialManager .create(context)
45+ // [END android_identity_initialize_credman]
46+
47+ // Placeholder for TAG log value.
48+ val TAG = " "
49+ /* *
50+ * Retrieves a passkey from the credential manager.
51+ *
52+ * @param creationResult The result of the passkey creation operation.
53+ * @param context The activity context from the Composable, to be used in Credential Manager APIs
54+ * @return The [GetCredentialResponse] object containing the passkey, or null if an error occurred.
55+ */
56+ @RequiresApi(Build .VERSION_CODES .UPSIDE_DOWN_CAKE )
57+ fun signInFlow (
58+ creationResult : JSONObject ,
59+ activityContext : Context ,
60+ ) {
61+ val requestJson = creationResult.toString()
62+ // [START android_identity_get_password_passkey_options]
63+ // Retrieves the user's saved password for your app from their
64+ // password provider.
65+ val getPasswordOption = GetPasswordOption ()
66+
67+ // Get passkey from the user's public key credential provider.
68+ val getPublicKeyCredentialOption = GetPublicKeyCredentialOption (
69+ requestJson = requestJson
70+ )
71+ // [END android_identity_get_password_passkey_options]
72+ var result: GetCredentialResponse
73+ // [START android_identity_get_credential_request]
74+ val credentialRequest = GetCredentialRequest (
75+ listOf (getPasswordOption, getPublicKeyCredentialOption),
76+ )
77+ // [END android_identity_get_credential_request]
78+ runBlocking {
79+ // getPrepareCredential request
80+ // [START android_identity_prepare_get_credential]
81+ coroutineScope {
82+ val response = credentialManager.prepareGetCredential(
83+ GetCredentialRequest (
84+ listOf (
85+ getPublicKeyCredentialOption,
86+ getPasswordOption
87+ )
88+ )
89+ )
90+ }
91+ // [END android_identity_prepare_get_credential]
92+ // getCredential request without handling exception.
93+ // [START android_identity_launch_sign_in_flow_1]
94+ coroutineScope {
95+ try {
96+ result = credentialManager.getCredential(
97+ // Use an activity-based context to avoid undefined system UI
98+ // launching behavior.
99+ context = activityContext,
100+ request = credentialRequest
101+ )
102+ handleSignIn(result)
103+ } catch (e: GetCredentialException ) {
104+ // Handle failure
105+ }
106+ }
107+ // [END android_identity_launch_sign_in_flow_1]
108+ // getCredential request adding some exception handling.
109+ // [START android_identity_handle_exceptions_no_credential]
110+ coroutineScope {
111+ try {
112+ result = credentialManager.getCredential(
113+ context = activityContext,
114+ request = credentialRequest
115+ )
116+ } catch (e: GetCredentialException ) {
117+ Log .e(" CredentialManager" , " No credential available" , e)
118+ }
119+ }
120+ // [END android_identity_handle_exceptions_no_credential]
121+ }
122+ }
123+
124+ // [START android_identity_launch_sign_in_flow_2]
125+ fun handleSignIn (result : GetCredentialResponse ) {
126+ // Handle the successfully returned credential.
127+ val credential = result.credential
128+
129+ when (credential) {
130+ is PublicKeyCredential -> {
131+ val responseJson = credential.authenticationResponseJson
132+ // Share responseJson i.e. a GetCredentialResponse on your server to
133+ // validate and authenticate
134+ }
135+
136+ is PasswordCredential -> {
137+ val username = credential.id
138+ val password = credential.password
139+ // Use id and password to send to your server to validate
140+ // and authenticate
141+ }
142+
143+ is CustomCredential -> {
144+ // If you are also using any external sign-in libraries, parse them
145+ // here with the utility functions provided.
146+ if (credential.type == ExampleCustomCredential .TYPE ) {
147+ try {
148+ val ExampleCustomCredential =
149+ ExampleCustomCredential .createFrom(credential.data)
150+ // Extract the required credentials and complete the authentication as per
151+ // the federated sign in or any external sign in library flow
152+ } catch (e: ExampleCustomCredential .ExampleCustomCredentialParsingException ) {
153+ // Unlikely to happen. If it does, you likely need to update the dependency
154+ // version of your external sign-in library.
155+ Log .e(TAG , " Failed to parse an ExampleCustomCredential" , e)
156+ }
157+ } else {
158+ // Catch any unrecognized custom credential type here.
159+ Log .e(TAG , " Unexpected type of credential" )
160+ }
161+ }
162+ else -> {
163+ // Catch any unrecognized credential type here.
164+ Log .e(TAG , " Unexpected type of credential" )
165+ }
166+ }
167+ }
168+ // [END android_identity_launch_sign_in_flow_2]
169+ }
170+
171+ sealed class ExampleCustomCredential {
172+ class ExampleCustomCredentialParsingException : Throwable () {}
173+
174+ companion object {
175+ fun createFrom (data : Bundle ): PublicKeyCredential {
176+ return PublicKeyCredential (" " )
177+ }
178+
179+ const val TYPE : String = " "
180+ }
181+ }
0 commit comments