> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Describes how to identify user attributes that you do not want to save in Auth0 databases.

# Add User Attributes to Deny List

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

If there are user fields that should not be stored in Auth0 databases due to privacy reasons, you can add them to the Deny List. To add attributes to the Deny List, make a `PATCH` call to the Update Connection endpoint of the <Tooltip tip="Management API: A product to allow customers to perform administrative tasks." cta="View Glossary" href="/docs/glossary?term=Management+API">Management API</Tooltip>.

1. Get a valid access token to access the `/patch_connections_by_id` [endpoint](https://auth0.com/docs/api/management/v2#!/Connections/patch_connections_by_id). The token must include the `update:connections` scope. See [Management API Access Tokens](/docs/secure/tokens/access-tokens/management-api-access-tokens) for details.
2. With the access token and the list of attributes to be denied, call the API. Here is an example HTTP request that denies two attributes: ethnicity and gender. Keep in mind you need to retrieve the options object and send the whole object in your PATCH request as there is no "merge" when you only update one or two values.

<AuthCodeGroup>
  ```bash cURL theme={null}
      curl --request PATCH \
    --url 'https://{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID' \
    --header 'authorization: Bearer YOUR_TOKEN' \
    --header 'content-type: application/json' \
    --data '{"options": {"non_persistent_attrs": ["ethnicity", "gender"]}}'

  ```

  ```csharp C# theme={null}
      var client = new RestClient("https://{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID");
  var request = new RestRequest(Method.PATCH);
  request.AddHeader("authorization", "Bearer YOUR_TOKEN");
  request.AddHeader("content-type", "application/json");
  request.AddParameter("application/json", "{"options": {"non_persistent_attrs": ["ethnicity", "gender"]}}", ParameterType.RequestBody);
  IRestResponse response = client.Execute(request);

  ```

  ```go Go theme={null}
      package main

  import (
    "fmt"
    "strings"
    "net/http"
    "io/ioutil"
  )

  func main() {

    url := "https://{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID"

    payload := strings.NewReader("{"options": {"non_persistent_attrs": ["ethnicity", "gender"]}}")

    req, _ := http.NewRequest("PATCH", url, payload)

    req.Header.Add("authorization", "Bearer YOUR_TOKEN")
    req.Header.Add("content-type", "application/json")

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

  }

  ```

  ```java Java theme={null}
      HttpResponse<String> response = Unirest.patch("https://{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID")
    .header("authorization", "Bearer YOUR_TOKEN")
    .header("content-type", "application/json")
    .body("{"options": {"non_persistent_attrs": ["ethnicity", "gender"]}}")
    .asString();

  ```

  ```javascript Node.JS theme={null}
      var axios = require("axios").default;

  var options = {
    method: 'PATCH',
    url: 'https://{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID',
    headers: {authorization: 'Bearer YOUR_TOKEN', 'content-type': 'application/json'},
    data: {options: {non_persistent_attrs: ['ethnicity', 'gender']}}
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });

  ```

  ```php PHP theme={null}
      $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_POSTFIELDS => "{"options": {"non_persistent_attrs": ["ethnicity", "gender"]}}",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer YOUR_TOKEN",
      "content-type: application/json"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }

  ```

  ```python Python theme={null}
      import http.client

  conn = http.client.HTTPSConnection("")

  payload = "{"options": {"non_persistent_attrs": ["ethnicity", "gender"]}}"

  headers = {
      'authorization': "Bearer YOUR_TOKEN",
      'content-type': "application/json"
      }

  conn.request("PATCH", "/{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID", payload, headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))

  ```

  ```ruby Ruby theme={null}
      require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/api/v2/connections/YOUR_CONNECTION_ID")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Patch.new(url)
  request["authorization"] = 'Bearer YOUR_TOKEN'
  request["content-type"] = 'application/json'
  request.body = "{"options": {"non_persistent_attrs": ["ethnicity", "gender"]}}"

  response = http.request(request)
  puts response.read_body

  ```
</AuthCodeGroup>

Where:

1. `{yourConnectionId}` is the [connection ID](/docs/authenticate/identity-providers/locate-the-connection-id) for which these attributes will be denied.
2. `{yourToken}` is the access token you received in the previous step.
3. `options.non_persistent_attrs` object holds an array of the attributes that will be denied. If the claim that you want to deny is being sent by an upstream Identity Provider (IdP), you should set the claim exactly as sent by the upstream IdP. For example, for a claim received as `https://acme.com/temporary_idtoken`, the above sample `non_persistent_attrs` object would read:

   ```json wrap lines theme={null}
   {"non_persistent_attrs": ["ethnicity", "gender", "https://acme.com/temporary_idtoken"]}
   ```

## Limitations

* Only [root fields](/docs/manage-users/user-accounts/user-profiles/user-profile-structure) (such as `user.name` or `user.phone_number`) can be denied.

  * If `user.name` or `user.nickname` are denied, they will not be included in tokens.
  * If `user.email` is denied, the value cannot be mapped to a custom claim. For example, in a rule, `context.idToken[namespace + 'work_email'] = user.email` would not work.
* When you deny attributes, they will still be available via rules and outgoing tokens. However, if any of the following apply, the Deny List attributes will **not** be included in tokens:

  * You have enabled multi-factor authentication (MFA)
  * You have performed a redirect via rules
  * Your app is using delegation (and you haven't set `scope = passthrough`)
  * Your app is using impersonation
  * You have enabled the **Use Auth0 instead of the IdP to do Single Sign-On** setting (legacy tenants only)
* For SAMLP connections, if you enable Debug mode, your logs will contain information on the Deny List attributes

If any of these limitations are unacceptable, you can write a [rule](/docs/customize/rules) to encrypt the data and have the data persist to the `user.app_metadata` object.

## Learn more

* [Revoke Access to APIs Using Application Grants](/docs/get-started/applications/revoke-api-access)
* [Auth0 IP Addresses for Allow Lists](/docs/secure/security-guidance/data-security/allowlist)
