Repository: auth0/auth0-python

Issue:
Add X-Forwarded-For header to Get Token requests [SDK-1941]
**Please do not report security vulnerabilities here**. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.

**Thank you in advance for helping us to improve this library!** Your attention to detail here is greatly appreciated and will help us respond as quickly as possible. For general support or usage questions, use the [Auth0 Community](https://community.auth0.com/) or [Auth0 Support](https://support.auth0.com/). Finally, to avoid duplicates, please search existing Issues before submitting one here.

By submitting an Issue to this repository, you agree to the terms within the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md).

### Describe the problem you'd like to have solved

> I currently have an API that my customers hit to get a token.  The API then uses Python to call Auth0 to exchange credentials for a token.  The code uses `GetToken.login()`, `GetToken.client_credentials`, and `GetToken.refresh_token`.  I've noticed that the API supports using the X-Forwarded-For header so that I could include the customer's IP address and Auth0 would use that IP address for any anomaly detection and for logging activity instead of all customers being tied to my API's IP address.  However, the auth0-python library does not support adding the X-Forwarded-For header to the request.

### Describe the ideal solution

> The auth0-python `GetToken` methods support providing an X-Forwarded-For header to the request to the Auth0 API.  This could either be a generic optional `headers` argument added to the method and those headers get added to the request or it could be a specific optional `x_forwarded_for` argument that gets added to the request headers.  That would allow me to inspect the IP address of my incoming request and add that to the request sent to the Auth0 API.

## Alternatives and current work-arounds

> I currently don't have any work-arounds in place, which means Auth0 only sees the IP address of my API resulting in one bad user potentially impacting all users.  A possible work-around is to stop using the auth0-python library and to simply make requests directly to the Auth0 API myself.

### Additional context

> N/A


Discussion:

Patch:
diff --git a/auth0/authentication/get_token.py b/auth0/authentication/get_token.py
index 9de8929..a7321b8 100644
--- a/auth0/authentication/get_token.py
+++ b/auth0/authentication/get_token.py
@@ -125,6 +125,7 @@ class GetToken(AuthenticationBase):
         realm: str | None = None,
         audience: str | None = None,
         grant_type: str = "http://auth0.com/oauth/grant-type/password-realm",
+        forwarded_for: str | None = None,
     ) -> Any:
         """Calls /oauth/token endpoint with password-realm grant type
 
@@ -152,9 +153,16 @@ class GetToken(AuthenticationBase):
             grant_type (str, optional): Denotes the flow you're using. For password realm
             use http://auth0.com/oauth/grant-type/password-realm
 
+            forwarded_for (str, optional): End-user IP as a string value. Set this if you want
+            brute-force protection to work in server-side scenarios.
+            See https://auth0.com/docs/get-started/authentication-and-authorization-flow/avoid-common-issues-with-resource-owner-password-flow-and-attack-protection
+
         Returns:
             access_token, id_token
         """
+        headers = None
+        if forwarded_for:
+            headers = {"auth0-forwarded-for": forwarded_for}
 
         return self.authenticated_post(
             f"{self.protocol}://{self.domain}/oauth/token",
@@ -167,6 +175,7 @@ class GetToken(AuthenticationBase):
                 "audience": audience,
                 "grant_type": grant_type,
             },
+            headers=headers,
         )
 
     def refresh_token(


Test patch:
diff --git a/auth0/test/authentication/test_get_token.py b/auth0/test/authentication/test_get_token.py
index f2c0b34..7e91f63 100644
--- a/auth0/test/authentication/test_get_token.py
+++ b/auth0/test/authentication/test_get_token.py
@@ -189,6 +189,22 @@ class TestGetToken(unittest.TestCase):
             },
         )
 
+    @mock.patch("auth0.rest.RestClient.post")
+    def test_login_with_forwarded_for(self, mock_post):
+        g = GetToken("my.domain.com", "cid", client_secret="clsec")
+
+        g.login(username="usrnm", password="pswd", forwarded_for="192.168.0.1")
+
+        args, kwargs = mock_post.call_args
+
+        self.assertEqual(args[0], "https://my.domain.com/oauth/token")
+        self.assertEqual(
+            kwargs["headers"],
+            {
+                "auth0-forwarded-for": "192.168.0.1",
+            },
+        )
+
     @mock.patch("auth0.rest.RestClient.post")
     def test_refresh_token(self, mock_post):
         g = GetToken("my.domain.com", "cid", client_secret="clsec")