Skip to content

Commit

Permalink
Update Shrine README.md
Browse files Browse the repository at this point in the history
Change-Id: If7d26ddf8b79f912f5b58bd54c83a386cdeeb678
  • Loading branch information
Neelansh Sahai committed Feb 21, 2025
1 parent a129209 commit 77a53ee
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 13 deletions.
35 changes: 34 additions & 1 deletion Shrine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This sample app implements the following use cases:
* Generate a new passkey for an existing account
* Store the credentials for created accounts in the user's Google Password Manager account.
* Sign in flow with passkeys support
* Sign in flow with restore credentials support
* Logout from the account.

## Requirements
Expand Down Expand Up @@ -200,6 +201,38 @@ This section describes how to send a sign-in response to the server and authenti
2. If successful, the user has been signed in and you can redirect them to the home screen.


### **Restore credentials of a returning user on a new device**

This section describes how to implement restore credentials

1. On a successful user authentication, create a Restore Key

1. Call `AuthRepository`'s `registerPasskeyCreationRequest` method

2. With the PasskeyCreationRequest recieved from the above method, call `CredentialManagerUtils`'s `createRestoreKey` method

3. Then call `AuthRepository`'s `registerPasskeyCreationResponse` method


2. Once on a new device, check if there is any restore key present on the device or not (brought to the new device in the process of Backup and Restore)

1. Call `AuthRepository`'s `signInWithPasskeysRequest` method

2. With the PasskeyCreationRequest recieved from the above method, call `CredentialManagerUtils`'s `getRestoreKey` method

3. If there is a RestoreKey present this will return a `GenericCredentialManagerResponse.GetPasskeySuccess` else this will return a `GenericCredentialManagerResponse.Error`


3. Sign in using the found Restore Key

1. If a restore key is found in the above step, simply use it to sign-in using `AuthRepository`'s `signInWithPasskeysResponse` method


4. Delete a Restore Key

1. If a user logs out of the app, make sure to clear the stored restore key by calling `CredentialManagerUtils`'s `deleteRestoreKey`


## **Specific use case handling**

- When there are no passkeys associated with accounts registered, the developer should catch the exception code and let the user know that first he needs to create a passkey before they try to fetch it.
Expand All @@ -219,4 +252,4 @@ To build a debug signed version of this sample app, you need to update the `API_

Shrine is distributed under the terms of the Apache License (Version 2.0). See the license for more information.

**
**
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ class CredentialManagerUtils @Inject constructor(
restoreCredentialRequest,
) as CreateRestoreCredentialResponse
} catch (e: Exception) {
e.printStackTrace()
return GenericCredentialManagerResponse.Error(errorMessage = e.message ?: "")
}
return GenericCredentialManagerResponse.CreatePasskeySuccess(createPasskeyResponse = credentialResponse)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ fun AuthenticationScreen(
) {
val uiState = viewModel.uiState.collectAsState().value
val errorDialogViewModel: ErrorDialogViewModel = hiltViewModel()
var shouldCheckForRestoreKey by remember { mutableStateOf(true) }
var isFirstCheckForRestoreKey by remember { mutableStateOf(true) }

// Passing in the lambda / context to the VM
val context = LocalContext.current
val createRestoreKey = {
viewModel.createRestoreKey(
updateCredMan = { createRestoreCredObject ->
createRestoreKeyOnCredMan = { createRestoreCredObject ->
credentialManagerUtils.createRestoreKey(
context = context,
requestResult = createRestoreCredObject
Expand All @@ -100,8 +100,8 @@ fun AuthenticationScreen(
)
}

if (shouldCheckForRestoreKey) {
shouldCheckForRestoreKey = false
if (isFirstCheckForRestoreKey) {
isFirstCheckForRestoreKey = false
viewModel.checkForStoredRestoreKey(
getRestoreKey = { requestResult ->
credentialManagerUtils.getRestoreKey(requestResult, context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fun RegisterScreen(
val context = LocalContext.current
val createRestoreKey = {
viewModel.createRestoreKey(
updateCredMan = { createRestoreCredObject ->
createRestoreKeyOnCredMan = { createRestoreCredObject ->
credentialManagerUtils.createRestoreKey(
context = context,
requestResult = createRestoreCredObject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,18 +152,18 @@ class AuthenticationViewModel @Inject constructor(
/**
* Creates a restore key by registering a new passkey.
*
* @param updateCredMan A suspend function that takes a [JSONObject] and returns a
* @param createRestoreKeyOnCredMan A suspend function that takes a [JSONObject] and returns a
* [GenericCredentialManagerResponse]. This function is responsible for creating
* the restore key.
*
* @see GenericCredentialManagerResponse
*/
fun createRestoreKey(
updateCredMan: suspend (createRestoreCredRequestObj: JSONObject) -> GenericCredentialManagerResponse
createRestoreKeyOnCredMan: suspend (createRestoreCredRequestObj: JSONObject) -> GenericCredentialManagerResponse
) {
viewModelScope.launch {
repository.registerPasskeyCreationRequest()?.let { data ->
val createRestoreKeyResponse = updateCredMan(data)
val createRestoreKeyResponse = createRestoreKeyOnCredMan(data)
if (createRestoreKeyResponse is GenericCredentialManagerResponse.CreatePasskeySuccess) {
repository.registerPasskeyCreationResponse(createRestoreKeyResponse.createPasskeyResponse)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class HomeViewModel @Inject constructor(

/**
* Signs out the user.
*
* @param deleteRestoreKey Lambda function received from Composable that triggers
* Credential Manager's deleteRestoreKey
*/
fun signOut(
deleteRestoreKey: suspend () -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,18 @@ class RegistrationViewModel @Inject constructor(
/**
* Creates a restore key by registering a new passkey.
*
* @param updateCredMan A suspend function that takes a [JSONObject] and returns a
* @param createRestoreKeyOnCredMan A suspend function that takes a [JSONObject] and returns a
* [GenericCredentialManagerResponse]. This function is responsible for creating
* the restore key.
*
* @see GenericCredentialManagerResponse
*/
fun createRestoreKey(
updateCredMan: suspend (createRestoreCredRequestObj: JSONObject) -> GenericCredentialManagerResponse
createRestoreKeyOnCredMan: suspend (createRestoreCredRequestObj: JSONObject) -> GenericCredentialManagerResponse
) {
viewModelScope.launch {
repository.registerPasskeyCreationRequest()?.let { data ->
val createRestoreKeyResponse = updateCredMan(data)
val createRestoreKeyResponse = createRestoreKeyOnCredMan(data)
if (createRestoreKeyResponse is GenericCredentialManagerResponse.CreatePasskeySuccess) {
repository.registerPasskeyCreationResponse(createRestoreKeyResponse.createPasskeyResponse)
}
Expand Down

0 comments on commit 77a53ee

Please sign in to comment.