Repository: getmoto/moto

Issue:
Cognito-idp: missing readable attributes in JWT payload
While testing the JWT payload verification part in my app, i've noticed that `moto` ignores the pool client readable attributes in JWT payload. 
Here's a working example:

**User Pool And App Client creation**
```py
cognito_client = boto3.client('cognito-idp')

create_response = cognito_client.create_user_pool(
    PoolName='user_pool'
)
client_id = cognito_client.create_user_pool_client(
    UserPoolId=create_response['UserPool']['Id'],
    ClientName='mock_pool_client',
    ReadAttributes=['custom:readable_attribute']
)['UserPoolClient']['ClientId']
```
**User Creation**
```py
user = cognito_client.admin_create_user(
    UserPoolId=create_response['UserPool']['Id'],
    Username='mock@user.com',
    UserAttributes=[{
            'Name': 'custom:readable_attribute',
            'Value': 'readable_value'
    }],
    TemporaryPassword='temporary_password'
)['User']
```
**User Confirmation and Token Retrieving**
````py
init_auth_response = cognito_client.admin_initiate_auth(
    UserPoolId=user_pool_id,
    ClientId=client_id,
    AuthFlow='ADMIN_NO_SRP_AUTH',
    AuthParameters={
        'USERNAME': user['Username'],
        'PASSWORD': 'temporary_password'
    },
)

auth_response = cognito_client.respond_to_auth_challenge(
    ClientId=client_id,
    Session=init_auth_response['Session'],
    ChallengeName=init_auth_response['ChallengeName'],
    ChallengeResponses={
        'USERNAME': user['Username'],
        'NEW_PASSWORD': 'definitive_password'
    }
)
````
In this way, we have the user's access token in `auth_response['AuthenticationResult']['AccessToken']`.

The token payload should be like this:
```json
{
    "iss": "https://cognito-idp.eu-central-1.amazonaws.com/5f74a2d1-1965-4010-b5cd-a889e71abfab",
    "sub": "3e61257c-a209-4cbe-b408-da69c00f4352",
    "aud": "ecbe867f-9fac-42ee-8eea-e05e95157896",
    "token_use": "id",
    "auth_time": 1533646833,
    "exp": 1533650433,
    "custom:readable_attribute": "readable_value"
}
```
Instead, the payload appears to be like this:
```json
{
    "iss": "https://cognito-idp.eu-central-1.amazonaws.com/5f74a2d1-1965-4010-b5cd-a889e71abfab",
    "sub": "3e61257c-a209-4cbe-b408-da69c00f4352",
    "aud": "ecbe867f-9fac-42ee-8eea-e05e95157896",
    "token_use": "id",
    "auth_time": 1533646833,
    "exp": 1533650433,
}
```


Discussion:

Resolving patch:
diff --git a/moto/cognitoidp/models.py b/moto/cognitoidp/models.py
--- a/moto/cognitoidp/models.py
+++ b/moto/cognitoidp/models.py
@@ -84,7 +84,11 @@ def create_refresh_token(self, client_id, username):
         return refresh_token
 
     def create_access_token(self, client_id, username):
-        access_token, expires_in = self.create_jwt(client_id, username)
+        extra_data = self.get_user_extra_data_by_client_id(
+            client_id, username
+        )
+        access_token, expires_in = self.create_jwt(client_id, username,
+                                                   extra_data=extra_data)
         self.access_tokens[access_token] = (client_id, username)
         return access_token, expires_in
 
@@ -97,6 +101,21 @@ def create_tokens_from_refresh_token(self, refresh_token):
         id_token, _ = self.create_id_token(client_id, username)
         return access_token, id_token, expires_in
 
+    def get_user_extra_data_by_client_id(self, client_id, username):
+        extra_data = {}
+        current_client = self.clients.get(client_id, None)
+        if current_client:
+            for readable_field in current_client.get_readable_fields():
+                attribute = list(filter(
+                    lambda f: f['Name'] == readable_field,
+                    self.users.get(username).attributes
+                ))
+                if len(attribute) > 0:
+                    extra_data.update({
+                        attribute[0]['Name']: attribute[0]['Value']
+                    })
+        return extra_data
+
 
 class CognitoIdpUserPoolDomain(BaseModel):
 
@@ -138,6 +157,9 @@ def to_json(self, extended=False):
 
         return user_pool_client_json
 
+    def get_readable_fields(self):
+        return self.extended_config.get('ReadAttributes', [])
+
 
 class CognitoIdpIdentityProvider(BaseModel):
 


Test patch:
diff --git a/tests/test_cognitoidp/test_cognitoidp.py b/tests/test_cognitoidp/test_cognitoidp.py
--- a/tests/test_cognitoidp/test_cognitoidp.py
+++ b/tests/test_cognitoidp/test_cognitoidp.py
@@ -6,6 +6,7 @@
 import uuid
 
 from jose import jws
+
 from moto import mock_cognitoidp
 import sure  # noqa
 
@@ -399,15 +400,22 @@ def authentication_flow(conn):
     username = str(uuid.uuid4())
     temporary_password = str(uuid.uuid4())
     user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
+    user_attribute_name = str(uuid.uuid4())
+    user_attribute_value = str(uuid.uuid4())
     client_id = conn.create_user_pool_client(
         UserPoolId=user_pool_id,
         ClientName=str(uuid.uuid4()),
+        ReadAttributes=[user_attribute_name]
     )["UserPoolClient"]["ClientId"]
 
     conn.admin_create_user(
         UserPoolId=user_pool_id,
         Username=username,
         TemporaryPassword=temporary_password,
+        UserAttributes=[{
+            'Name': user_attribute_name,
+            'Value': user_attribute_value
+        }]
     )
 
     result = conn.admin_initiate_auth(
@@ -446,6 +454,9 @@ def authentication_flow(conn):
         "access_token": result["AuthenticationResult"]["AccessToken"],
         "username": username,
         "password": new_password,
+        "additional_fields": {
+            user_attribute_name: user_attribute_value
+        }
     }
 
 
@@ -475,6 +486,8 @@ def test_token_legitimacy():
     access_claims = json.loads(jws.verify(access_token, json_web_key, "RS256"))
     access_claims["iss"].should.equal(issuer)
     access_claims["aud"].should.equal(client_id)
+    for k, v in outputs["additional_fields"].items():
+        access_claims[k].should.equal(v)
 
 
 @mock_cognitoidp