# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
from typing import List, NamedTuple

from flask_appbuilder.security.sqla.models import User
from marshmallow import Schema, fields
from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field

from airflow.api_connexion.parameters import validate_istimezone
from airflow.api_connexion.schemas.role_and_permission_schema import RoleSchema


class UserCollectionItemSchema(SQLAlchemySchema):
    """user collection item schema"""

    class Meta:
        """Meta"""

        model = User
        dateformat = "iso"

    user_id = auto_field('id', dump_only=True)
    first_name = auto_field()
    last_name = auto_field()
    username = auto_field()
    active = auto_field(dump_only=True)
    email = auto_field()
    last_login = auto_field(dump_only=True)
    login_count = auto_field(dump_only=True)
    fail_login_count = auto_field(dump_only=True)
    roles = fields.List(fields.Nested(RoleSchema, only=('name',)))
    created_on = auto_field(validate=validate_istimezone, dump_only=True)
    changed_on = auto_field(validate=validate_istimezone, dump_only=True)


class UserSchema(UserCollectionItemSchema):
    """User schema"""

    password = auto_field(load_only=True)


class UserCollection(NamedTuple):
    """User collection"""

    users: List[User]
    total_entries: int


class UserCollectionSchema(Schema):
    """User collection schema"""

    users = fields.List(fields.Nested(UserCollectionItemSchema))
    total_entries = fields.Int()


user_collection_item_schema = UserCollectionItemSchema()
user_schema = UserSchema()
user_collection_schema = UserCollectionSchema()

airflow/api_connexion/schemas/user_schema.py
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
from typing import List, NamedTuple

from flask_appbuilder.security.sqla.models import User
from marshmallow import Schema, fields
from marshmallow_sqlalchemy import SQLAlchemySchema, auto_field

from airflow.api_connexion.parameters import validate_istimezone
from airflow.api_connexion.schemas.role_and_permission_schema import RoleSchema


class UserCollectionItemSchema(SQLAlchemySchema):
    """user collection item schema"""

    class Meta:
        """Meta"""

        model = User
        dateformat = "iso"

    first_name = auto_field()
    last_name = auto_field()
    username = auto_field()
    active = auto_field(dump_only=True)
    email = auto_field()
    last_login = auto_field(dump_only=True)
    login_count = auto_field(dump_only=True)
    fail_login_count = auto_field(dump_only=True)
    roles = fields.List(fields.Nested(RoleSchema, only=('name',)))
    created_on = auto_field(validate=validate_istimezone, dump_only=True)
    changed_on = auto_field(validate=validate_istimezone, dump_only=True)


class UserSchema(UserCollectionItemSchema):
    """User schema"""

    password = auto_field(load_only=True)


class UserCollection(NamedTuple):
    """User collection"""

    users: List[User]
    total_entries: int


class UserCollectionSchema(Schema):
    """User collection schema"""

    users = fields.List(fields.Nested(UserCollectionItemSchema))
    total_entries = fields.Int()


user_collection_item_schema = UserCollectionItemSchema()
user_schema = UserSchema()
user_collection_schema = UserCollectionSchema()

airflow/api_connexion/schemas/user_schema.py
diff --git a/airflow/api_connexion/openapi/v1.yaml b/airflow/api_connexion/openapi/v1.yaml
index 7885e8d912c5a..08e3595276725 100644
--- a/airflow/api_connexion/openapi/v1.yaml
+++ b/airflow/api_connexion/openapi/v1.yaml
@@ -1499,10 +1499,6 @@ components:
         A user object
       type: object
       properties:
-        user_id:
-          type: integer
-          description: The user id
-          readOnly: true
         first_name:
           type: string
           description: The user firstname
diff --git a/airflow/api_connexion/schemas/user_schema.py b/airflow/api_connexion/schemas/user_schema.py
index c78493fd44df4..f7b1dea6e1648 100644
--- a/airflow/api_connexion/schemas/user_schema.py
+++ b/airflow/api_connexion/schemas/user_schema.py
@@ -33,7 +33,6 @@ class Meta:
         model = User
         dateformat = "iso"
 
-    user_id = auto_field('id', dump_only=True)
     first_name = auto_field()
     last_name = auto_field()
     username = auto_field()
diff --git a/tests/api_connexion/endpoints/test_user_endpoint.py b/tests/api_connexion/endpoints/test_user_endpoint.py
index b52c54cfdd112..f5247501ba7f2 100644
--- a/tests/api_connexion/endpoints/test_user_endpoint.py
+++ b/tests/api_connexion/endpoints/test_user_endpoint.py
@@ -98,7 +98,6 @@ def test_should_respond_200(self):
             'last_name': 'test1',
             'login_count': None,
             'roles': [],
-            'user_id': users[0].id,
             'username': 'TEST_USER1',
         }
 
diff --git a/tests/api_connexion/schemas/test_user_schema.py b/tests/api_connexion/schemas/test_user_schema.py
index d11198bd504c7..619e6d4c6a2ec 100644
--- a/tests/api_connexion/schemas/test_user_schema.py
+++ b/tests/api_connexion/schemas/test_user_schema.py
@@ -71,12 +71,11 @@ def test_serialize(self):
         self.session.commit()
         user = self.session.query(User).filter(User.email == TEST_EMAIL).first()
         deserialized_user = user_collection_item_schema.dump(user)
-        # No password in dump
+        # No user_id and password in dump
         assert deserialized_user == {
             'created_on': DEFAULT_TIME,
             'email': 'test@example.org',
             'changed_on': DEFAULT_TIME,
-            'user_id': user.id,
             'active': None,
             'last_login': None,
             'last_name': 'Bar',
@@ -103,13 +102,12 @@ def test_serialize(self):
         self.session.commit()
         user = self.session.query(User).filter(User.email == TEST_EMAIL).first()
         deserialized_user = user_schema.dump(user)
-        # No password in dump
+        # No user_id and password in dump
         assert deserialized_user == {
             'roles': [],
             'created_on': DEFAULT_TIME,
             'email': 'test@example.org',
             'changed_on': DEFAULT_TIME,
-            'user_id': user.id,
             'active': None,
             'last_login': None,
             'last_name': 'Bar',

Remove 'user_id', 'role_id' from User and Role in OpenAPI schema 
Would be good to remove the 'id' of both User and Role schemas from what is dumped in REST API endpoints. ID of User and Role table are sensitive data that would be fine to hide from the endpoints

