Cognito: support for partial UpdateUserPoolClient calls
- Lingua principale
- Java
- Stelle
- 2.6k
- Fork
- 1k
- Merge medio
- 2g 9h
- PR unite (30g)
- 51
Descrizione
### Describe the feature
The `UpdateUserPoolClient` should support partial updates instead of having to provide every single parameter in the request.
### Use Case
Currently, the process to update a user pool client through the SDK is very cumbersome. For example, if we only want to update the `callbackURLs` on an existing user pool client, we have to pass every single property with the *existing* value to the `UpdateUserPoolClientRequest`. This is because Cognito [doesn't support partial updates](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPoolClient.html):
> If you don't provide a value for an attribute, Amazon Cognito sets it to its default value.
```kotlin
import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient
import software.amazon.awssdk.services.cognitoidentityprovider.model.DescribeUserPoolClientRequest
import software.amazon.awssdk.services.cognitoidentityprovider.model.UpdateUserPoolClientRequest
class CognitoClient(
private val cognitoConfig: CognitoConfig,
private val cognitoClient: CognitoIdentityProviderClient,
) {
// redacted other methods
fun addCallbackUrlToAppClient(clientId: String, callbackUrl: String) {
val describeUserPoolClientRequest = DescribeUserPoolClientRequest.builder()
.clientId(clientId)
.userPoolId(cognitoConfig.userPoolId)
.build()
val existingUserPoolClient = cognitoClient
.describeUserPoolClient(describeUserPoolClientRequest)
.userPoolClient()
val existingCallbackUrls = existingUserPoolClient.callbackURLs()
if (existingCallbackUrls.contains(callbackUrl)) {
logger.info("Callback URL $callbackUrl already exists for client $clientId, skipping.")
return
}
// We need to copy the list because it's immutable.
val updatedCallbackUrls = existingCallbackUrls.toMutableList()
updatedCallbackUrls.add(callbackUrl)
/**
* From the Cognito docs: "WARNING - If you don't provide a value for an attribute,
* Amazon Cognito sets it to its default value."
*
* So here we are, setting all the attributes to their already existing values.
*/
val updateRequest = UpdateUserPoolClientRequest.builder()
.accessTokenValidity(existingUserPoolClient.accessTokenValidity())
.allowedOAuthFlows(existingUserPoolClient.allowedOAuthFlows())
.allowedOAuthFlowsUserPoolClient(existingUserPoolClient.allowedOAuthFlowsUserPoolClient())
.allowedOAuthScopes(existingUserPoolClient.allowedOAuthScopes())
.analyticsConfiguration(existingUserPoolClient.analyticsConfiguration())
.authSessionValidity(existingUserPoolClient.authSessionValidity())
// This is the only field we're _actually_ changing
.callbackURLs(updatedCallbackUrls)
.clientId(existingUserPoolClient.clientId())
.clientName(existingUserPoolClient.clientName())
.defaultRedirectURI(existingUserPoolClient.defaultRedirectURI())
.enablePropagateAdditionalUserContextData(existingUserPoolClient.enablePropagateAdditionalUserContextData())
.enableTokenRevocation(existingUserPoolClient.enableTokenRevocation())
.explicitAuthFlows(existingUserPoolClient.explicitAuthFlows())
.idTokenValidity(existingUserPoolClient.idTokenValidity())
.logoutURLs(existingUserPoolClient.logoutURLs())
.preventUserExistenceErrors(existingUserPoolClient.preventUserExistenceErrors())
.readAttributes(existingUserPoolClient.readAttributes())
.refreshTokenValidity(existingUserPoolClient.refreshTokenValidity())
.supportedIdentityProviders(existingUserPoolClient.supportedIdentityProviders())
.tokenValidityUnits(existingUserPoolClient.tokenValidityUnits())
.userPoolId(existingUserPoolClient.userPoolId())
.writeAttributes(existingUserPoolClient.writeAttributes())
.build()
cognitoClient.updateUserPoolClient(updateRequest)
logger.info("Successfully added callback URL $callbackUrl to Cognito App Client $clientId")
}
}
```
### Proposed Solution
This probably will need updates on the Cognito service side. However, I do think it would be nice if the SDK could provide a convenience method in the meantime. I guess something like:
```kotlin
import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient
import software.amazon.awssdk.services.cognitoidentityprovider.model.DescribeUserPoolClientRequest
import software.amazon.awssdk.services.cognitoidentityprovider.model.UpdateUserPoolClientRequest
class CognitoClient(
private val cognitoConfig: CognitoConfig,
private val cognitoClient: CognitoIdentityProviderClient,
) {
// redacted other methods
fun addCallbackUrlToAppClient(clientId: String, callbackUrl: String) {
val describeUserPoolClientRequest = DescribeUserPoolClientRequest.builder()
.clientId(clientId)
.userPoolId(cognitoConfig.userPoolId)
.build()
val existingUserPoolClient = cognitoClient
.describeUserPoolClient(describeUserPoolClientRequest)
.userPoolClient()
val existingCallbackUrls = existingUserPoolClient.callbackURLs()
if (existingCallbackUrls.contains(callbackUrl)) {
logger.info("Callback URL $callbackUrl already exists for client $clientId, skipping.")
return
}
// We need to copy the list because it's immutable.
val updatedCallbackUrls = existingCallbackUrls.toMutableList()
updatedCallbackUrls.add(callbackUrl)
val updateRequest = UpdateUserPoolClientRequest.builder()
.callbackURLs(updatedCallbackUrls)
.clientId(existingUserPoolClient.clientId())
.build()
cognitoClient.updateUserPoolClient(updateRequest, true)
logger.info("Successfully added callback URL $callbackUrl to Cognito App Client $clientId")
}
}
```
Note that `updateUserPoolClient` now takes a second parameter. This parameter could be named something like `keepExistingParameters` and default to `false`, so it's not a breaking change. If `true`, it could get the existing user pool (either by doing a `describeUserPoolClient` under the hood or require an existing `UserPoolClientType` to be passed).
### Other Information
Related Cognito docs: https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_UpdateUserPoolClient.html
### Acknowledgements
- [ ] I may be able to implement this feature request
- [ ] This feature might incur a breaking change
### AWS Java SDK version used
2.25.50
### JDK version used
17.0.10
### Operating System and version
macOS 14.4.1
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Iniziare con la documentazione dell’API AWS UpdateUserPoolClient e con gli entry point denominati UpdateUserPoolClientRequest, updateUserPoolClient e DescribeUserPoolClient. Confrontare il comportamento proposto di keepExistingParameters con il contratto esistente dell’SDK e determinare come gli aggiornamenti parziali debbano rimanere retrocompatibili; il lavoro richiede un design concordato e la relativa validazione.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- aws, java, kotlin
- Ambito
- authentication, cloud
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100