Edited at

Cognito User Pool の DeveloperOnlyAttribute って何?


結論

管理者向け API でしか読み取れないユーザー属性っぽいです。

クライアント向け API では読み書きできません。管理者向け API でも書き込みはできません。


どういう事?

CloudFormation の Cognito User Pool リファレンスを眺めていた所、個人的に見慣れないオプションを発見しました。

Amazon Cognito UserPool SchemaAttribute - AWS CloudFormation

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-schemaattribute.html


DeveloperOnlyAttribute

属性タイプが開発者のみであるかを指定します。

Type: Boolean

Required: No


開発者のみとは?

気になるので Cognito 側の API リファレンスを確認してみます。

SchemaAttributeType - Amazon Cognito Identity Provider

https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_SchemaAttributeType.html


DeveloperOnlyAttribute

Specifies whether the attribute type is developer only.

Type: Boolean

Required: No


属性タイプが developer only か指定する的な。

この文脈で言う developer とは一体・・・


DeveloperOnlyAttribute を有効化した User Pool を作ってみる

DeveloperOnlyAttribute を有効化した myattribute というカスタム属性を定義して User Pool を作ってみます。

勉強も兼ねて CloudFormation 使っていきます。


myuserpool.yaml

Resources:

DeveloperOnlyAttributeEnabledCognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: DeveloperOnlyAttributeEnabledCognitoUserPool
Schema:
- Name: myattribute
AttributeDataType: String
DeveloperOnlyAttribute: True

CloudFormation テンプレートを作成したら、 AWS CLI からデプロイ

$ aws cloudformation deploy --template-file ./myuserpool.yaml --stack-name developer-only-attribute-enabled-cognito-user-pool

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - developer-only-attribute-enabled-cognito-user-pool

出来上がった User Pool の設定を確認してみます。

$ aws cognito-idp describe-user-pool --user-pool-id ap-northeast-1_xxx

{
"UserPool": {
"Id": "ap-northeast-1_xxx",
"Name": "DeveloperOnlyAttributeEnabledCognitoUserPool",
"Policies": {
"PasswordPolicy": {
"MinimumLength": 8,
"RequireUppercase": true,
"RequireLowercase": true,
"RequireNumbers": true,
"RequireSymbols": true,
"TemporaryPasswordValidityDays": 7
}
},
"LambdaConfig": {},
"LastModifiedDate": 1565706803.41,
"CreationDate": 1565706803.41,
"SchemaAttributes": [
{
"Name": "sub",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": false,
"Required": true,
"StringAttributeConstraints": {
"MinLength": "1",
"MaxLength": "2048"
}
},
{
"Name": "name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "given_name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "family_name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "middle_name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "nickname",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "preferred_username",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "profile",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "picture",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "website",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "email",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "email_verified",
"AttributeDataType": "Boolean",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false
},
{
"Name": "gender",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "birthdate",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "10",
"MaxLength": "10"
}
},
{
"Name": "zoneinfo",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "locale",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "phone_number",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "phone_number_verified",
"AttributeDataType": "Boolean",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false
},
{
"Name": "address",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "updated_at",
"AttributeDataType": "Number",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"NumberAttributeConstraints": {
"MinValue": "0"
}
},
{
"Name": "dev:custom:myattribute",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": true,
"Mutable": false,
"Required": false,
"StringAttributeConstraints": {}
}
],
"VerificationMessageTemplate": {
"DefaultEmailOption": "CONFIRM_WITH_CODE"
},
"MfaConfiguration": "OFF",
"EstimatedNumberOfUsers": 0,
"EmailConfiguration": {
"EmailSendingAccount": "COGNITO_DEFAULT"
},
"UserPoolTags": {},
"AdminCreateUserConfig": {
"AllowAdminCreateUserOnly": false,
"UnusedAccountValidityDays": 7
},
"Arn": "arn:aws:cognito-idp:ap-northeast-1:123456789012:userpool/ap-northeast-1_xxx"
}
}

情報が盛り沢山ですが、今回着目するのは次の箇所です。

            {

"Name": "dev:custom:myattribute",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": true,
"Mutable": false,
"Required": false,
"StringAttributeConstraints": {}
}

myattribute というカスタム属性が作成されて、 DeveloperOnlyAttributetrue になってますね。

普通のカスタム属性は custom:attributename のような形式ですが、 dev:custom:attributename のように、 dev: がプレフィックスとして追加されています。


ユーザーを作ってみる

まず、ユーザー作るのにアプリクライアントが必要なので作ります。

$ aws cognito-idp create-user-pool-client --user-pool-id ap-northeast-1_xxx --client-name myappclient --explicit-auth-flows "ADMIN_NO_SRP_AUTH"

{
"UserPoolClient": {
"UserPoolId": "ap-northeast-1_xxx",
"ClientName": "myappclient",
"ClientId": "6c0fdunb8s2ijns0ue2lfr8iia",
"LastModifiedDate": 1565707946.052,
"CreationDate": 1565707946.052,
"RefreshTokenValidity": 30,
"ExplicitAuthFlows": [
"ADMIN_NO_SRP_AUTH"
],
"AllowedOAuthFlowsUserPoolClient": false
}
}

これでユーザー作成の準備ができたので、カスタム属性を設定して sign up してみます。

$ aws cognito-idp sign-up --client-id 6c0fdunb8s2ijns0ue2lfr8iia --username sampleuser --password 'Passw@rd1234' --user-attributes Name=dev:custom:myattribute,Value=hogehoge

{
"UserConfirmed": false,
"UserSub": "bb64ae42-b532-4182-8efa-efc67662a345"
}

で、後で認証するため confirm しておきます。

$ aws cognito-idp admin-confirm-sign-up --user-pool-id ap-northeast-1_xxx --username sampleuser

admin-confirm-sign-up コマンドは、成功時に特に出力は無いので admin-get-user コマンドでユーザー状況を確認します。

$ aws cognito-idp admin-get-user --user-pool-id ap-northeast-1_xxx --username sampleuser

{
"Username": "sampleuser",
"UserAttributes": [
{
"Name": "sub",
"Value": "bb64ae42-b532-4182-8efa-efc67662a345"
},
{
"Name": "dev:custom:myattribute",
"Value": "hogehoge"
}
],
"UserCreateDate": 1565708213.268,
"UserLastModifiedDate": 1565708247.72,
"Enabled": true,
"UserStatus": "CONFIRMED"
}

UserStatusCONFIRMED になってれば OK


認証して、カスタム属性を取得してみる

ADMIN_NO_SRP_AUTH を使ってサクッと認証します。

$ aws cognito-idp admin-initiate-auth --user-pool-id ap-northeast-1_xxx --client-id 6c0fdunb8s2ijns0ue2lfr8iia --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=sampleuser,PASSWORD=Passw@rd1234

{
"ChallengeParameters": {},
"AuthenticationResult": {
"AccessToken": "xxx",
"ExpiresIn": 3600,
"TokenType": "Bearer",
"RefreshToken": "yyy",
"IdToken": "zzz"
}
}

ここでレスポンスされる AccessToken を使っていきます。


クライアント向け API でカスタム属性を読み書きしてみる

Cognito User Pool には、IAM のクレデンシャルを使って API 呼び出しを行う管理者向け API と、認証時に発行されるアクセストークンを使って API 呼び出しを行うクライアント向け API があります。

リソースのアクセス許可 - Amazon Cognito

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/resource-permissions.html#amazon-cognito-signed-versus-unsigned-apis


署名された API と署名されていない API

AWS 認証情報で署名された API は、IAM ポリシーで制限することができます。次の Cognito API は署名されていないため、IAM ポリシーで制限することはできません。


署名されていない API を使って、カスタム属性の読み書きを試してみます。

$ aws cognito-idp get-user --access-token xxx

{
"Username": "sampleuser",
"UserAttributes": [
{
"Name": "sub",
"Value": "bb64ae42-b532-4182-8efa-efc67662a345"
}
]
}

UserAttributesdev:custom:myattribute が含まれていません。

クライアント向け API で無理やり dev:custom:myattribute を変更しようとしてみます。

$ aws cognito-idp update-user-attributes --user-attributes Name=dev:custom:myattribute,Value=fugafuga --access-token xxx

An error occurred (InvalidParameterException) when calling the UpdateUserAttributes operation: Invalid user attributes: custom:myattribute: Attribute cannot be updated.

ズバリなエラーメッセージですね。

カスタム属性として custom:myattribute は存在しているようですが、更新はできないようです。

削除も試してみます。

$ aws cognito-idp delete-user-attributes --user-attribute-names dev:custom:myattribute --access-token xxx

An error occurred (InvalidParameterException) when calling the DeleteUserAttributes operation: Invalid user attributes: user.dev:custom:myattribute: Attribute cannot be updated.

user.dev:custom:myattribute 属性は存在するようですが、削除も含めた更新ができないようです。


管理者向け API でカスタム属性を読み書きしてみる

AWS 認証情報での署名が必要な、管理者向け API で色々ためしてみます。

既にユーザー作成時に試してますが、改めて admin-get-user でユーザー情報を取得してみます。

$ aws cognito-idp admin-get-user --user-pool-id ap-northeast-1_xxx --username sampleuser

{
"Username": "sampleuser",
"UserAttributes": [
{
"Name": "sub",
"Value": "bb64ae42-b532-4182-8efa-efc67662a345"
},
{
"Name": "dev:custom:myattribute",
"Value": "hogehoge"
}
],
"UserCreateDate": 1565708213.268,
"UserLastModifiedDate": 1565708247.72,
"Enabled": true,
"UserStatus": "CONFIRMED"
}

dev:custom:myattribute 属性の情報が参照できています。

では、次は更新を試してみます。

$ aws cognito-idp admin-update-user-attributes --user-pool-id ap-northeast-1_xxx --username sampleuser --user-attributes Name=dev:custom:myattribute,Value=fugafuga

An error occurred (InvalidParameterException) when calling the AdminUpdateUserAttributes operation: Invalid user attributes: custom:myattribute: Attribute cannot be updated.

管理者向け API でも属性の更新ができないようです。

一応、管理者向け API での削除も試してみます。

$ aws cognito-idp admin-delete-user-attributes --user-pool-id ap-northeast-1_xxx --username sampleuser --user-attribute-names dev:custom:myattribute

An error occurred (InvalidParameterException) when calling the AdminDeleteUserAttributes operation: Invalid user attributes: user.dev:custom:myattribute: Attribute cannot be updated.

というわけで削除もできません。


検証結果まとめ、結論

検証結果をまとめます。

読み取り
更新
削除

クライアント API
(get-user, update-attribute, delete-attribute)
できない
できない
できない

管理者向け API
(admin-get-user, admin-update-attribute, admin-delete-attribute)
できる
できない
できない

というわけで、クライアント向け API では読み書きできず、管理者向け API では読み込み可能であるものの書き込みはできない状態でした。

つまり DeveloperOnlyAttribute は管理者向け API でのみ読み込むことが出来る属性と言えそうです。

DeveloperOnlyAttribute の Developer とは、 IAM のクレデンシャルを持つ開発者というようなニュアンスっぽいですね。

また、公式フォーラムに以下のような情報がありました。

AWS Developer Forums: DeveloperOnlyAttribute - what is the effect of the property?

https://forums.aws.amazon.com/thread.jspa?threadID=267841&tstart=0


This for the attributes that developer doesn't want to expose to the end users.


DeveloperOnlyAttribute はエンドユーザーに見せたくない属性に使う設定のようです。

個人的に具体的なユースケースが思い浮かびませんが・・・

ちなみに、検証で作成したリソースの後片付けは CloudFormation で作成したので、スタックを削除すれば OK です

$ aws cloudformation delete-stack --stack-name developer-only-attribute-enabled-cognito-user-pool

以上、 DeveloperOnlyAttribute について調べてみたメモでした。

こういう用途で DeveloperOnlyAttribute 使ってるとか、検証内容について指摘等あれば是非コメントください。