> ## Documentation Index
> Fetch the complete documentation index at: https://doc.lucidworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SharePoint Online V1

> The SharePoint Online V1 connector retrieves data from cloud-based SharePoint repositories.

export const schema = {
  "type": "object",
  "title": "SharePoint Online (deprecated)",
  "description": "A crawler for SharePoint online",
  "required": ["id", "connector", "type", "pipeline", "properties"],
  "properties": {
    "category": {
      "type": "string",
      "title": "Category",
      "default": "Repository",
      "hints": ["hidden", "readonly"]
    },
    "id": {
      "type": "string",
      "title": "Datasource ID",
      "description": "Unique name for this datasource.",
      "minLength": 1,
      "pattern": "^[a-zA-Z0-9_-]+$"
    },
    "connector": {
      "type": "string",
      "title": "Connector Type",
      "description": "Connector Type.",
      "hints": ["hidden"],
      "minLength": 1
    },
    "type": {
      "type": "string",
      "title": "Datasource Type",
      "description": "Datasource type supported by the selected connector type.",
      "hints": ["hidden"],
      "minLength": 1
    },
    "pipeline": {
      "type": "string",
      "title": "Pipeline ID",
      "description": "Name of an existing index pipeline for processing documents.",
      "minLength": 1
    },
    "description": {
      "type": "string",
      "title": "Description",
      "description": "Optional description for this datasource."
    },
    "type_description": {
      "type": "string",
      "title": "Type Description",
      "default": "A crawler for SharePoint online",
      "hints": ["hidden", "readonly"]
    },
    "parserId": {
      "type": "string",
      "title": "Parser",
      "description": "Parser used when parsing raw content. For some connectors, a configuration to 'retry' parsing if an error occurs is available as an advanced setting"
    },
    "properties": {
      "type": "object",
      "title": "Properties",
      "description": "Datasource configuration properties",
      "required": ["startLinks", "enable_security_trimming", "f.username", "f.password"],
      "properties": {
        "startLinks": {
          "type": "array",
          "title": "Start Links",
          "description": "SharePoint Sites, SharePoint Lists e.g. http(s)://<site_url>/Lists/<list_name>/AllItems.aspx and SharePoint Libraries e.g. http(s)://<site_url>/<library_name>/Forms/AllItems.aspx are allowed.",
          "items": {
            "type": "string",
            "minLength": 1
          }
        },
        "collection": {
          "type": "string",
          "title": "Collection",
          "description": "Collection documents will be indexed to.",
          "hints": ["hidden"],
          "pattern": "^[a-zA-Z0-9_-]+$"
        },
        "db": {
          "type": "object",
          "title": "Connector DB",
          "description": "Type and properties for a ConnectorDB implementation to use with this datasource.",
          "required": ["type"],
          "properties": {
            "type": {
              "type": "string",
              "title": "Implementation Class Name",
              "description": "Fully qualified class name of ConnectorDb implementation.",
              "default": "com.lucidworks.connectors.db.impl.MapDbConnectorDb",
              "minLength": 1
            },
            "inlinks": {
              "type": "boolean",
              "title": "Process Inlinks?",
              "description": "Keep track of incoming links. This negatively impacts performance and size of DB.",
              "default": false
            },
            "aliases": {
              "type": "boolean",
              "title": "Process Aliases?",
              "description": "Keep track of original URI-s that resolved to the current URI. This negatively impacts performance and size of DB.",
              "default": false
            },
            "inv_aliases": {
              "type": "boolean",
              "title": "Process Inverted Aliases?",
              "description": "Keep track of target URI-s that the current URI resolves to. This negatively impacts performance and size of DB.",
              "default": false
            }
          },
          "hints": ["hidden"]
        },
        "dedupe": {
          "type": "boolean",
          "title": "Dedupe documents",
          "description": "If true, documents will be deduplicated. Deduplication can be done based on an analysis of the content, on the content of a specific field, or by a JavaScript function. If neither a field nor a script are defined, content analysis will be used.",
          "default": false,
          "hints": ["advanced"]
        },
        "dedupeField": {
          "type": "string",
          "title": "Dedupe field",
          "description": "Field to be used for dedupe. Define either a field or a dedupe script, otherwise the full raw content of each document will be used.",
          "hints": ["advanced"]
        },
        "dedupeScript": {
          "type": "string",
          "title": "Dedupe script",
          "description": "Custom javascript to dedupe documents. The script must define a 'genSignature(content){}' function, but can use any combination of document fields. The function must return a string.",
          "hints": ["advanced", "code", "code/javascript"]
        },
        "dedupeSaveSignature": {
          "type": "boolean",
          "title": "Save dedupe signature",
          "description": "If true,the signature used for dedupe will be stored in a 'dedupeSignature_s' field. Note this may cause errors about 'immense terms' in that field.",
          "default": false,
          "hints": ["advanced"]
        },
        "delete": {
          "type": "boolean",
          "title": "Delete dead URIs",
          "description": "Set to true to remove documents from the index when they can no longer be accessed as unique documents.",
          "default": true
        },
        "deleteErrorsAfter": {
          "type": "integer",
          "title": "Fetch failure allowance",
          "description": "Number of fetch failures to tolerate before removing a document from the index. The default of -1 means no fetch failures will be removed.",
          "default": -1
        },
        "fetchThreads": {
          "type": "integer",
          "title": "Fetch threads",
          "description": "The number of threads to use during fetching. The default is 5.",
          "default": 5
        },
        "emitThreads": {
          "type": "integer",
          "title": "Emit threads",
          "description": "The number of threads used to send documents from the connector to the index pipeline. The default is 5.",
          "default": 5
        },
        "chunkSize": {
          "type": "integer",
          "title": "Fetch batch size",
          "description": "The number of items to batch for each round of fetching. A higher value can make crawling faster, but memory usage is also increased. The default is 1.",
          "default": 1,
          "hints": ["advanced"]
        },
        "fetchDelayMS": {
          "type": "integer",
          "title": "Fetch delay",
          "description": "Number of milliseconds to wait between fetch requests. The default is 0. This property can be used to throttle a crawl if necessary.",
          "default": 0,
          "hints": ["advanced"]
        },
        "refreshAll": {
          "type": "boolean",
          "title": "Recrawl all items",
          "description": "Set to true to always recrawl all items found in the crawldb.",
          "default": true,
          "hints": ["advanced"]
        },
        "refreshStartLinks": {
          "type": "boolean",
          "title": "Recrawl start links",
          "description": "Set to true to recrawl items specified in the list of start links.",
          "default": false,
          "hints": ["advanced"]
        },
        "refreshErrors": {
          "type": "boolean",
          "title": "Recrawl errors",
          "description": "Set to true to recrawl items that failed during the last crawl.",
          "default": false,
          "hints": ["advanced"]
        },
        "refreshOlderThan": {
          "type": "integer",
          "title": "Recrawl age",
          "description": "Number of seconds to recrawl items whose last fetched date is longer ago than this value.",
          "default": -1,
          "hints": ["advanced"]
        },
        "refreshIDPrefixes": {
          "type": "array",
          "title": "Recrawl ID prefixes",
          "description": "A prefix to recrawl all items whose IDs begin with this value.",
          "hints": ["advanced"],
          "items": {
            "type": "string"
          }
        },
        "refreshIDRegexes": {
          "type": "array",
          "title": "Recrawl ID regexes",
          "description": "A regular expression to recrawl all items whose IDs match this pattern.",
          "hints": ["advanced"],
          "items": {
            "type": "string"
          }
        },
        "refreshScript": {
          "type": "string",
          "title": "Recrawl script",
          "description": "A JavaScript function ('shouldRefresh()') to customize the items recrawled. ",
          "hints": ["advanced", "code", "code/javascript"]
        },
        "forceRefresh": {
          "type": "boolean",
          "title": "Force recrawl",
          "description": "Set to true to recrawl all items even if they have not changed since the last crawl.",
          "default": false,
          "hints": ["advanced"]
        },
        "forceRefreshClearSignatures": {
          "type": "boolean",
          "title": "Clear signatures",
          "description": "If true, signatures will be cleared if force recrawl is enabled.",
          "default": true,
          "hints": ["advanced"]
        },
        "retryEmit": {
          "type": "boolean",
          "title": "Retry emits",
          "description": "Set to true for emit batch failures to be retried on a document-by-document basis.",
          "default": true,
          "hints": ["advanced"]
        },
        "depth": {
          "type": "integer",
          "title": "Max crawl depth",
          "description": "Number of levels in a directory or site tree to descend for documents.",
          "default": -1
        },
        "maxItems": {
          "type": "integer",
          "title": "Max items",
          "description": "Maximum number of documents to fetch. The default (-1) means no limit.",
          "default": -1
        },
        "failFastOnStartLinkFailure": {
          "type": "boolean",
          "title": "Fail crawl if start links are invalid",
          "description": "If true, when Fusion cannot connect to any of the provided start links, the crawl is stopped and an exception logged.",
          "default": true,
          "hints": ["advanced"]
        },
        "crawlDBType": {
          "type": "string",
          "title": "Crawl database type",
          "description": "The type of crawl database to use, in-memory or on-disk.",
          "enum": ["in-memory", "on-disk"],
          "default": "on-disk",
          "hints": ["advanced"]
        },
        "commitAfterItems": {
          "type": "integer",
          "title": "Commit After This Many Items",
          "description": "Commit the crawlDB to disk after this many items have been received. A smaller number here will result in a slower crawl because of commits to disk being more frequent; conversely, a larger number here will cause a resumed job after a crash to need to recrawl more records.",
          "default": 10000,
          "hints": ["advanced"]
        },
        "initial_mapping": {
          "type": "object",
          "title": "Initial field mapping",
          "description": "Provides mapping of fields before documents are sent to an index pipeline.",
          "properties": {
            "skip": {
              "type": "boolean",
              "title": "Skip This Stage",
              "description": "Set to true to skip this stage.",
              "default": false,
              "hints": ["advanced"]
            },
            "label": {
              "type": "string",
              "title": "Label",
              "description": "A unique label for this stage.",
              "hints": ["advanced"],
              "maxLength": 255
            },
            "condition": {
              "type": "string",
              "title": "Condition",
              "description": "Define a conditional script that must result in true or false. This can be used to determine if the stage should process or not.",
              "hints": ["code", "code/javascript", "advanced"]
            },
            "reservedFieldsMappingAllowed": {
              "type": "boolean",
              "title": "Allow System Fields Mapping?",
              "default": false,
              "hints": ["advanced"]
            },
            "retentionMappings": {
              "type": "array",
              "title": "Field Retention",
              "description": "Fields that should be kept or deleted",
              "default": [],
              "hints": ["advanced"],
              "items": {
                "type": "object",
                "required": ["field"],
                "properties": {
                  "field": {
                    "type": "string",
                    "title": "Field",
                    "description": "The name of the field to operate on.",
                    "hints": ["advanced"]
                  },
                  "operation": {
                    "type": "string",
                    "title": "Operation",
                    "description": "The type of operation to perform: keep (default) or delete",
                    "enum": ["keep", "delete"],
                    "default": "keep",
                    "hints": ["advanced"]
                  }
                }
              }
            },
            "updateMappings": {
              "type": "array",
              "title": "Field Value Updates",
              "description": "Values that should be added to or set on a field. When a value is added, any values previously on the field will be retained. When a value is set, any values previously on the field will be overwritten.",
              "default": [],
              "hints": ["advanced"],
              "items": {
                "type": "object",
                "required": ["field", "value"],
                "properties": {
                  "field": {
                    "type": "string",
                    "title": "Field",
                    "description": "The name of the field to operate on.",
                    "hints": ["advanced"]
                  },
                  "value": {
                    "type": "string",
                    "title": "Value",
                    "description": "The value to add to or set on the field.",
                    "hints": ["advanced"]
                  },
                  "operation": {
                    "type": "string",
                    "title": "Operation",
                    "description": "The type of operation to perform: add (default) or set.",
                    "enum": ["add", "set"],
                    "default": "add",
                    "hints": ["advanced"]
                  }
                }
              }
            },
            "translationMappings": {
              "type": "array",
              "title": "Field Translations",
              "description": "Fields that should be moved or copied to another field. When a field is moved, the values from the source field are moved over to the target field and the source field is removed. When a field is copied, the values from the source field are copied over to the target field and the source field is retained.",
              "default": [{
                "source": "charSet",
                "target": "charSet_s",
                "operation": "move"
              }, {
                "source": "fetchedDate",
                "target": "fetchedDate_dt",
                "operation": "move"
              }, {
                "source": "lastModified",
                "target": "lastModified_dt",
                "operation": "move"
              }, {
                "source": "signature",
                "target": "dedupeSignature_s",
                "operation": "move"
              }, {
                "source": "length",
                "target": "length_l",
                "operation": "move"
              }, {
                "source": "mimeType",
                "target": "mimeType_s",
                "operation": "move"
              }, {
                "source": "parent",
                "target": "parent_s",
                "operation": "move"
              }, {
                "source": "owner",
                "target": "owner_s",
                "operation": "move"
              }, {
                "source": "group",
                "target": "group_s",
                "operation": "move"
              }],
              "hints": ["advanced"],
              "items": {
                "type": "object",
                "required": ["source", "target"],
                "properties": {
                  "source": {
                    "type": "string",
                    "title": "Source Field",
                    "description": "The name of the field to operate on.",
                    "hints": ["advanced"]
                  },
                  "target": {
                    "type": "string",
                    "title": "Target Field",
                    "description": "The name of the target field.",
                    "hints": ["advanced"]
                  },
                  "operation": {
                    "type": "string",
                    "title": "Operation",
                    "description": "The type of operation to perform: copy (default) or move.",
                    "enum": ["copy", "move"],
                    "default": "copy",
                    "hints": ["advanced"]
                  }
                }
              }
            },
            "unmappedRule": {
              "type": "object",
              "title": "Unmapped Fields",
              "description": "Fields not mapped by the above rules. By default, any remaining fields will be kept on the document.",
              "properties": {
                "keep": {
                  "type": "boolean",
                  "title": "Keep",
                  "description": "Keep all unmapped fields",
                  "default": true,
                  "hints": ["advanced"]
                },
                "delete": {
                  "type": "boolean",
                  "title": "Delete",
                  "description": "Delete all unmapped fields",
                  "default": false,
                  "hints": ["advanced"]
                },
                "fieldToMoveValuesTo": {
                  "type": "string",
                  "title": "Move",
                  "description": "Move all unmapped field values to this field",
                  "hints": ["advanced"]
                },
                "fieldToCopyValuesTo": {
                  "type": "string",
                  "title": "Copy",
                  "description": "Copy all unmapped field values to this field",
                  "hints": ["advanced"]
                },
                "valueToAddToUnmappedFields": {
                  "type": "string",
                  "title": "Add",
                  "description": "Add this value to all unmapped fields",
                  "hints": ["advanced"]
                },
                "valueToSetOnUnmappedFields": {
                  "type": "string",
                  "title": "Set",
                  "description": "Set this value on all unmapped fields",
                  "hints": ["advanced"]
                }
              },
              "default": {
                "keep": true,
                "delete": false,
                "fieldToMoveValuesTo": "",
                "fieldToCopyValuesTo": "",
                "valueToAddToUnmappedFields": "",
                "valueToSetOnUnmappedFields": ""
              }
            }
          },
          "category": "Field Transformation",
          "categoryPriority": 7,
          "hints": ["advanced"],
          "unsafe": false
        },
        "enable_security_trimming": {
          "type": "object",
          "title": "Enable Security Trimming",
          "properties": {
            "f.enable_sharepoint_security_trimming": {
              "type": "boolean",
              "title": "Enable security trimming",
              "description": "Enable indexing and query-time security-trimming of SharePoint users/groups (i.e. in addition to users/groups in Active Directory)",
              "default": true
            },
            "f.security_filter_cache": {
              "type": "boolean",
              "title": "Enable local security filter cache",
              "description": "Cache of document access control rules. This cache will not be shared with any other SharePoint datasources.",
              "default": false
            },
            "f.global_security_filter_cache": {
              "type": "boolean",
              "title": "Enable global security filter cache",
              "description": "Enable shared caching of access-control filters across datasources. This cache will be shared with other SharePoint datasources.",
              "default": false
            },
            "f.cache_expiration_time": {
              "type": "integer",
              "title": "Security cache expiration time",
              "description": "Time in seconds before the local and global security filter cache entries expire.",
              "default": 7200,
              "hints": ["advanced"]
            },
            "f.user_group_cache": {
              "type": "boolean",
              "title": "Enable User Group Caching in Solr",
              "description": "When this option is selected, the crawl process will store all user's LDAP and SharePoint groups a Solr sidecar collection such that a user's groups do not need to be looked up at query time. This is not to be mistaken with the other global and local security-filter caches of which cache the access-control filter of the user.",
              "default": true
            },
            "f.user_group_cache_collection_name": {
              "type": "string",
              "title": "User group cache Solr collection name",
              "description": "The name of the solr collection that will store this datsources' user group cache. This user group cache collection can be shared with other datasources. There is a `ds_id_s` field that is used to query user/groups separately.",
              "default": "sp_usr_grp_{datasource}"
            },
            "f.cache_max_size": {
              "type": "integer",
              "title": "Security cache max size",
              "description": "Maximum number of items to hold in the security filter cache.",
              "default": 1000,
              "hints": ["advanced"]
            },
            "f.ldap_host": {
              "type": "string",
              "title": "LDAP server host",
              "description": "Hostname of the LDAP or AD server where user information is stored."
            },
            "f.ldap_port": {
              "type": "integer",
              "title": "LDAP server port",
              "description": "Port for the LDAP or AD server.",
              "default": 389
            },
            "f.ldap_use_ssl": {
              "type": "boolean",
              "title": "LDAP server use ssl",
              "description": "Enable to use SSL when connecting to the LDAP or AD server.",
              "default": false
            },
            "f.ldap_search_base": {
              "type": "string",
              "title": "LDAP search base",
              "description": "Base node for LDAP or AD user and group searches."
            },
            "f.ldap_read_groups_type": {
              "type": "string",
              "title": "LDAP read groups type",
              "description": "Mode for reading groups from LDAP or AD.",
              "default": "TOKEN_GROUPS"
            },
            "f.ldap_follow_referrals": {
              "type": "boolean",
              "title": "LDAP referral",
              "description": "Indicates whether or not to follow LDAP referrals. Select this checkbox to \"follow\" referrals and un-select it to \"ignore\" referrals.",
              "default": true
            }
          }
        },
        "excludeExtensions": {
          "type": "array",
          "title": "Excluded file extensions",
          "description": "File extensions that should not to be fetched. This will limit this datasource to all extensions except this list.",
          "items": {
            "type": "string"
          }
        },
        "excludeRegexes": {
          "type": "array",
          "title": "Exclusive regexes",
          "description": "Regular expressions for URI patterns to exclude. This will limit this datasource to only URIs that do not match the regular expression.",
          "items": {
            "type": "string"
          }
        },
        "includeExtensions": {
          "type": "array",
          "title": "Included file extensions",
          "description": "File extensions to be fetched. This will limit this datasource to only these file extensions.",
          "items": {
            "type": "string"
          }
        },
        "includeRegexes": {
          "type": "array",
          "title": "Inclusive regexes",
          "description": "Regular expressions for URI patterns to include. This will limit this datasource to only URIs that match the regular expression.",
          "items": {
            "type": "string"
          }
        },
        "rewriteLinkScript": {
          "type": "string",
          "title": "URI rewrite script",
          "description": "A Javascript function 'rewriteLink(link) { }' to modify links to documents before they are fetched.",
          "hints": ["advanced", "code", "code/javascript"]
        },
        "diagnosticMode": {
          "type": "boolean",
          "title": "Diagnostic mode",
          "description": "Enable to print more detailed information to the logs about each request.",
          "default": false,
          "hints": ["advanced"]
        },
        "trackEmbeddedIDs": {
          "type": "boolean",
          "title": "Track embedded IDs?",
          "description": "Track IDs produced by splitters to enable dedupe and deletion of embedded content?",
          "default": true,
          "hints": ["advanced"]
        },
        "f.username": {
          "type": "string",
          "title": "SharePoint username",
          "description": "Name of a SharePoint user who has the required permissions to access SharePoint via the SOAP API. This user must be registered with the SharePoint Online authentication server; it is not necessarily the same as the user in Active Directory or LDAP."
        },
        "f.password": {
          "type": "string",
          "title": "SharePoint password",
          "description": "Password for the SharePoint user.",
          "hints": ["secret"]
        },
        "f.loginCookieRefreshRateMs": {
          "type": "integer",
          "title": "SharePoint Online Cookie Refresh Rate (ms)",
          "description": "The amount of time in milliseconds to re-use a SharePoint online cookie until fetching a new one. Ideally this will be set to a small bit less thank the max of the Cookies.",
          "default": 120000
        },
        "f.adUsername": {
          "type": "string",
          "title": "Active Directory Username",
          "description": "The active directory account username."
        },
        "f.adPassword": {
          "type": "string",
          "title": "Active Directory Password",
          "description": "The active directory account password.",
          "hints": ["secret"]
        },
        "f.domain": {
          "type": "string",
          "title": "NetBIOS domain",
          "description": "NETBIOS domain for the SharePoint crawl account. Example: LUCIDWORKS"
        },
        "f.dnsSuffix": {
          "type": "string",
          "title": "Fully qualified domain name",
          "description": "The Default fully qualified domain for users. Example: lucidworks.com"
        },
        "f.maxSizeBytes": {
          "type": "integer",
          "title": "Maximum file size (bytes)",
          "description": "Maximum size, in bytes, of a document to crawl.",
          "default": 4194304
        },
        "f.minSizeBytes": {
          "type": "integer",
          "title": "Minimum file size (bytes)",
          "description": "Minimum size, in bytes, of a document to crawl.",
          "default": 0
        },
        "f.avoid_ssl_hostname_verification": {
          "type": "boolean",
          "title": " Avoid SSL hostname verification ",
          "description": "Enable this in cases when the CN on the SSL certificate does not match the host name of the server.",
          "default": true
        },
        "f.sharepoint_services_timeout": {
          "type": "integer",
          "title": "SharePoint services timeout",
          "description": "Time in milliseconds to wait for a server response.",
          "default": 600000,
          "hints": ["advanced"]
        },
        "f.enable_http_headers_debugging": {
          "type": "boolean",
          "title": "Enable HTTP headers debugging",
          "description": "Prints DEBUG level information to the logs.",
          "default": false,
          "hints": ["advanced"]
        },
        "f.remove_prepended_ids": {
          "type": "boolean",
          "title": "Remove prepended IDs",
          "description": "If fields have been defined to include PrependIds, this option will remove those IDs before indexing.",
          "default": true,
          "hints": ["advanced"]
        },
        "f.log_sharepoint_xml": {
          "type": "boolean",
          "title": "Log SharePoint Soap XML",
          "description": "When analyzing SharePoint crawls, it can be helpful to log the Soap XML messages between Fusion and SharePoint. By selecting this, SharePoint will log the xml of all messages to the connectors log.",
          "default": false,
          "hints": ["advanced"]
        },
        "f.replace_invalid_xml_entities": {
          "type": "boolean",
          "title": "Replace invalid xml entities",
          "description": "Replace invalid xml entities to avoid the error: \\\"Unmarshalling Error: Illegal character entity: expansion character ...\\\"",
          "default": false,
          "hints": ["advanced"]
        },
        "f.sharepoint_online": {
          "type": "boolean",
          "title": "SharePoint Online",
          "default": true,
          "hints": ["hidden"]
        },
        "parserRetryCount": {
          "type": "integer",
          "title": "Max Parser Retries",
          "description": "The maximum number of times the configured parser will try getting content before giving up",
          "default": 0,
          "maximum": 5,
          "exclusiveMaximum": true,
          "minimum": 0,
          "exclusiveMinimum": false
        },
        "f.proxyType": {
          "type": "string",
          "title": "Proxy type",
          "description": "Type of proxy to use, if any. Allowed values are 'HTTP' and 'SOCKS'. Leave empty for no proxy.",
          "default": "HTTP",
          "hints": ["hidden"]
        },
        "f.proxyHost": {
          "type": "string",
          "title": "Proxy host",
          "description": "The address to use when connecting through the proxy."
        },
        "f.proxyPort": {
          "type": "integer",
          "title": "Proxy port",
          "description": "The port to use when connecting through the proxy. (HTTP or SOCKS)"
        },
        "f.enable_retry": {
          "type": "boolean",
          "title": "Retry requests",
          "description": "Enable this to make the connector automatically try again if a request to SharePoint fails unexpectedly",
          "default": true
        },
        "f.retry_attempts": {
          "type": "integer",
          "title": "Number of retries",
          "description": "If Retry requests is enabled, this number determines how many times the connector should retry a request before giving up",
          "default": 4
        },
        "f.index_items_discarded": {
          "type": "boolean",
          "title": "Index discarded document metadata",
          "description": "Enable to index discarded document metadata",
          "default": true
        }
      },
      "propertyGroups": [{
        "label": "Crawl History",
        "properties": ["crawlDBType", "commitAfterItems"]
      }, {
        "label": "Authentication",
        "properties": ["f.username", "f.password", "f.adUsername", "f.adPassword", "f.domain", "f.dnsSuffix", "f.loginCookieRefreshRateMs", "f.avoid_ssl_hostname_verification", "f.sharepoint_services_timeout", "f.enable_http_headers_debugging", "f.remove_prepended_ids", "f.proxyType", "f.proxyHost", "f.proxyPort"]
      }, {
        "label": "Security Trimming",
        "properties": ["enable_security_trimming"]
      }, {
        "label": "Dedupe",
        "properties": ["dedupe", "dedupeSaveSignature", "dedupeField", "dedupeScript"]
      }, {
        "label": "Crawl Performance",
        "properties": ["chunkSize", "fetchThreads", "fetchDelayMS", "emitThreads", "retryEmit", "failFastOnStartLinkFailure", "parserRetryCount", "f.enable_retry", "f.retry_attempts"]
      }, {
        "label": "Recrawl Rules",
        "properties": ["refreshAll", "refreshStartLinks", "refreshErrors", "refreshOlderThan", "refreshIDPrefixes", "refreshIDRegexes", "refreshScript", "forceRefresh", "forceRefreshClearSignatures"]
      }, {
        "label": "Field Mapping",
        "properties": ["initial_mapping"]
      }, {
        "label": "Limit Documents",
        "properties": ["includeRegexes", "excludeRegexes", "includeExtensions", "excludeExtensions", "depth", "maxItems", "f.maxSizeBytes", "f.minSizeBytes", "delete", "deleteErrorsAfter", "f.index_items_discarded"]
      }]
    }
  },
  "category": "Other",
  "categoryPriority": 1,
  "unsafe": false
};

export const SchemaParamFields = ({schema}) => {
  const sanitize = str => {
    if (typeof str !== "string") return str;
    return str.replace(/^"(.*)"$/s, "$1").replace(/\\/g, "").replace(/"/g, "'");
  };
  const formatDescription = str => {
    const s = sanitize(str);
    return (/[.!?]\)*$/).test(s) ? s : `${s}.`;
  };
  const {description, properties = {}, required: requiredProps = []} = schema;
  const visibleProps = useMemo(() => Object.entries(properties).filter(([, prop]) => !prop.hints?.includes("hidden")), [properties]);
  return <div>
      {description && <p>{formatDescription(description)}</p>}

      {visibleProps.map(([name, prop]) => {
    const isRequired = requiredProps.includes(name);
    const hasDefault = prop.default !== undefined;
    const rawDefault = prop.default;
    const isComplexDefault = hasDefault && (typeof rawDefault === "object" || typeof rawDefault === "string" && (rawDefault.length > 20 || rawDefault.includes('"')));
    const fieldProps = {
      key: name,
      body: prop.title || name,
      type: prop.type,
      ...prop.title && ({
        post: [<><span className="text-stone-400 dark:text-stone-500">API property: </span>{name}</>]
      }),
      ...isRequired && ({
        required: true
      }),
      ...!isComplexDefault && hasDefault ? {
        default: sanitize(String(rawDefault))
      } : {}
    };
    const isObject = prop.type === "object" && prop.properties;
    const isArrayOfObjects = prop.type === "array" && prop.items?.type === "object" && prop.items.properties;
    return <ParamField {...fieldProps}>
            {prop.description && <p>{formatDescription(prop.description)}</p>}

            {isComplexDefault && <div className="flex">
                <p>
                  <strong>Default:</strong>
                </p>
                <pre className="!my-0">
                  <code>
                    {JSON.stringify(rawDefault, null, 2)}
                  </code>
                </pre>
              </div>}

            {isArrayOfObjects && <div className="flex">
              <p>
                <strong>Object attributes:</strong>
              </p>
              <pre className="!my-0">
                <code>
                  {'{\n'}
                  {Object.entries(prop.items.properties).map(([iname, iprop]) => <>
                      {`  ${iname}`}
                      {prop.items?.required?.includes(iname) && <span style={{
      color: 'red'
    }}> required</span>}
                      {`: {\n    display name: ${sanitize(iprop.title || '')}\n    type: ${iprop.type}\n  }\n`}
                    </>)}
                  {'}'}
                </code>
              </pre>
              </div>}

            {isObject && <Expandable title="properties">
                <SchemaParamFields schema={{
      properties: prop.properties,
      required: prop.required
    }} />
              </Expandable>}
          </ParamField>;
  })}
    </div>;
};

export const LwTemplate = ({title = "Key questions to get you started", icon = "sparkles", cta = "Powered by Agent Studio", linkHref = "https://lucidworks.com/demo/?utm_source=docs&utm_medium=referral&utm_campaign=docs_cta_ai"}) => {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsLoaded(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);
  return <div className="lw-template-container">
      <Card title={title} icon={icon}>
        {isLoaded && <span dangerouslySetInnerHTML={{
    __html: `<lw-template id="a029c1a9-28be-427e-b0e1-5d918920246a"></lw-template
            >`
  }} />}
        <Link href={linkHref} className="agent-studio-link text-left text-gray-600 gap-2 dark:text-gray-400 text-sm font-medium flex flex-row items-center hover:text-primary dark:hover:text-primary-light group-hover:text-primary group-hover:dark:text-primary-light">Powered by Lucidworks Agent Studio</Link>
      </Card>
    </div>;
};

[localhost link]: http://localhost:3000/docs/fusion-connectors/connectors/v1/sharepoint-online

[mintlify link]: https://doc.lucidworks.com/docs/fusion-connectors/connectors/v1/sharepoint-online

[old doc.lw link]: https://doc.lucidworks.com/fusion-connectors/51

<Callout icon="plug" color="#A4C6F7" iconType="solid">
  **Compatible with Fusion version:** 4.0.0 through 5.3.5
</Callout>

Authentication for this connector requires a SharePoint user who has permissions to access SharePoint via the SOAP API. This user must be registered with the SharePoint Online authentication server; it is not necessarily the same as the user in Active Directory or LDAP.

<Note>
  Deprecation and removal notice

  This connector is deprecated as of Fusion 5.3 and is removed or expected to be removed as of Fusion 5.5. Use the SharePoint Optimized V2 connector instead.

  For more information about deprecations and removals, including possible alternatives, see [Deprecations and Removals](/docs/fusion-connectors/deprecations-and-removals).
</Note>

<LwTemplate />

## Learn more

<AccordionGroup>
  <Accordion title="Configure a Non-Administrative Crawl Account in SharePoint Online">
    The SharePoint connector retrieves content and metadata from an on-premises SharePoint repository.

    The steps below describe how to configure a crawl account in SharePoint Online without giving the account administrative access.

    ## Create a site collection administrator account

    To create a site collection administrator account, you must have administrator permissions for the site you want to crawl.

    1. Log in to the SharePoint Online admin center as a SharePoint administrator.
    2. Go to **Sites** > **Active sites** and select the site you want to crawl.
    3. Go to **Membership** > **Site Admins** and click **Add site admin**.
    4. Search for the user you want to designate as a site admin, then click **Add**.

    The user is now listed as a site admin.

    <Note>The site collection administrator only has control over the selected site and its sub-sites.</Note>

    ## Add a crawl permissions level

    To create a new permission level, click the gear symbol and go to **Site Settings > Site permissions**. Select **Permission Levels**, and click **Add a Permission Level**. Name the new permission level "Lucidworks Fusion Service Permission", and assign the following site permissions:

    | Name                           | Description                                                                                          |
    | ------------------------------ | ---------------------------------------------------------------------------------------------------- |
    | View Items                     | View items in lists and documents in document libraries.                                             |
    | Open Items                     | View the source of documents with server-side file handlers.                                         |
    | View Versions                  | View past versions of a list item or document.                                                       |
    | View Application Pages         | View forms, views, and application pages. Enumerate lists.                                           |
    | View Web Analytics Data        | View reports on Web site usage.                                                                      |
    | Browse Directories             | Enumerate files and folders in a Web site using SharePoint Designer and Web DAV interfaces.          |
    | View Pages                     | View pages in a Web site.                                                                            |
    | Enumerate Permissions          | Enumerate permissions on the Web site, list, folder, document, or list item.                         |
    | Browse User Information        | View information about users of the Web site.                                                        |
    | Use Remote Interfaces          | Use SOAP, Web DAV, the Client Object Model or SharePoint Designer interfaces to access the Web site. |
    | Open                           | Allows users to open a Web site, list, or folder in order to access items inside that container.     |
    | Edit Personal User Information | Allows a user to change his or her own user information, such as adding a picture.                   |

    ## Create a Fusion crawl group

    For ***each*** top-level site you want to be able to crawl, you must create a site permissions group and assign the permissions level you created previously. Go to **Site Settings > Site permissions**. Click the **Create Group** symbol and name the new group "Lucidworks Fusion Crawl Accounts". Add the site collection administrator, and any other user that you wish to have crawl permissions, to this group.

    The site collection administrator should now be able to crawl without administrator rights.

    ## Limitations of a non-administrative crawl account in SharePoint Online

    There are important limitations to crawling SharePoint Online with a non-administrative account. Only administrators are permitted to list site collections from SharePoint Online. To crawl multiple site collections from your SharePoint Online tenant, you must either:

    1. List the site collections in the *Start Links* explicitly, **or;**
    2. Provide a SharePoint administrator account when crawling SharePoint Online

    The image below illustrates what information a non-administrator user can crawl:

    <img src="https://mintcdn.com/lucidworks/de_1M1m_4TTyJqw0/assets/images/4.2/sponline-permission-config-03.png?fit=max&auto=format&n=de_1M1m_4TTyJqw0&q=85&s=f65b417257a6f138d67ef76d39837505" alt="Non-admin Crawl Permissions" width="411" height="516" data-path="assets/images/4.2/sponline-permission-config-03.png" />

    <Note>Although a non-administrator user can be allowed to list sub-sites in a site collection, the user cannot list the site collections of the tenant URL.</Note>
    For example, a non-administrator user may list the Sub-sites in `https://lucidworks.sharepoint.com/sites/sitecol`, such as `/sitecol/subsite1` and `/sitecol/subsite2`. However, only an administrator can list the site collections in `https://lucidworks.sharepoint.com`.
  </Accordion>

  <Accordion title="Crawl SharePoint Online with Minimal Throttling">
    These instructions are for how to design your crawl so Microsoft will not throttle you.
    Use this if you are starting a new deployment or getting chronic throttling as a strategy to architect the crawl using multiple accounts, splitting datasources, and chaining the scheduler.

    Some key points:

    * Identify traffic with a [custom user agent tied to an Azure app](#update-the-user-agent-string-to-link-to-an-azure-app).
    * [Divide and conquer](#divide-and-conquer-with-multiple-service-accounts) by splitting sites across multiple datasources and multiple service accounts.
    * Set [very low threads per datasource](#divide-and-conquer), but spread the load horizontally across accounts and datasources.
    * [Shape concurrency at the job level](#lucidworks-job-scheduler-to-limit-concurrent-datasources) by chaining jobs with the scheduler and controlling how many SharePoint jobs run at once.

    SharePoint Online is a shared cloud service. Indexing content with SharePoint Online is much slower than crawling SharePoint On-Premises servers. SharePoint Online throttles the traffic heavily, keeping the SharePoint services responsive and healthy.

    Microsoft has published a purposely vague article, which does not include a throttling algorithm, for further understanding [How to Avoid Throttling](https://docs.microsoft.com/en-us/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online).

    Based on the information provided, we will discuss the techniques currently used to eliminate throttling. These recommendations are subject to change, as this is an *evolving topic*.

    ### Update the user agent string to link to an Azure app

    Each SharePoint datasource requires your company name in the user agent string.

    **Example:**

    ```bash theme={"dark"}
    ISV|AcmeInc|Fusion/5.3
    ```

    This “decorates” traffic uniquely so Microsoft will know exactly who API calls are coming from.
    ***Do not use*** the default user agent string. It will not *uniquely identify* your company’s traffic.

    ### Divide and conquer with multiple service accounts

    SharePoint Online rate limits are due to multiple threads accessing SharePoint APIs concurrently. SharePoint sees that sort of traffic and throttles it heavily.

    To reduce the traffic and throttling:

    * Split SharePoint site collections between datasources.
    * Create multiple SharePoint Online service accounts and spread them across the datasources.

    **Example** - configured SharePoint online optimized connector datasource **SPO\_DS\_1**:

    ```bash theme={"dark"}
    Start links:
    https://tenant.sharepoint.com/sites/test1
    https://tenant.sharepoint.com/sites/test2
    https://tenant.sharepoint.com/sites/test3
    https://tenant.sharepoint.com/sites/test4
    https://tenant.sharepoint.com/sites/test5

    Service account: service.account@tenant.onmicrosoft.com
    Fetch Threads: 5
    Number of prefetch threads: 10
    User agent: ISV|YourCompanyName|Fusion/5.x.x
    ```

    The crawling will begin with great speed. However, eventually errors are generated in the logs:

    ```bash theme={"dark"}
    Error message: [429 TOO MANY REQUESTS]
    ```

    #### Divide and conquer

    1. Create five service accounts, exactly like the first.
    2. Create five datasources. Give each datasource its very own service account and a subset of the SharePoint site collections that are to be crawled.
    3. Set the fetch threads to 1.

    ##### Configuration results

    ```bash expandable theme={"dark"}
    * SPO_DS_1:\
    Start links: **<span>https://</span>tenant.sharepoint.com/sites/test1**\
    Service account: **\service.account@tenant1.onmicrosoft.com**\
    Fetch Threads: **1**\
    Number of prefetch threads: **1**
    * SPO_DS_2:\
    Start links: **<span>https://</span>tenant.sharepoint.com/sites/test2**\
    Service account: **\service.account@tenant2.onmicrosoft.com**\
    Fetch Threads: **1**\
    Number of prefetch threads: **1**
    * SPO_DS_3:\
    Start links: **<span>https://</span>tenant.sharepoint.com/sites/test3**\
    Service account: **\service.account@tenant3.onmicrosoft.com**\
    Fetch Threads: **1**\
    Number of prefetch threads: **1**
    * SPO_DS_4:\
    Start links: **<span>https://</span>tenant.sharepoint.com/sites/test4**\
    Service account: **\service.account@tenant4.onmicrosoft.com**\
    Fetch Threads: **1**\
    Number of prefetch threads: **1**
    * SPO_DS_5:\
    Start links: **<span>https://</span>tenant.sharepoint.com/sites/test5**\
    Service account: **\service.account@tenant5.onmicrosoft.com**\
    Fetch Threads: **1**\
    Number of prefetch threads: **1**
    ```

    The idea is to reduce rate limiting. Microsoft will see requests coming from five accounts rather than a single account. To prevent multiple SharePoint jobs from running concurrently, chain jobs.

    The key is to prevent Fusion from making too many SharePoint API requests to the SharePoint Online servers concurrently. If too aggressive, Microsoft will throttle.

    ### Lucidworks job scheduler to limit concurrent datasources

    In addition to limiting a single datasource from making to many connections as once, limit the number of SharePoint Online datasources running concurrently. To avoid too many concurrent datasources running, use the Lucidworks Job Scheduler to chain SharePoint datasources to run one at a time.

    See Schedule a Job

    Use the **“Trigger job after another data source completes”** feature.

    **Example single datasource at a time:**

    ```bash theme={"dark"}
    SPO_DS_1 Schedule: Every day at 06:00:00\
    SPO_DS_2 Schedule: Trigger job upon completion of SPO_DS_1\
    SPO_DS_3 Schedule: Trigger job upon completion of SPO_DS_2\
    SPO_DS_4 Schedule: Trigger job upon completion of SPO_DS_3\
    SPO_DS_5 Schedule: Trigger job upon completion of SPO_DS_4
    ```

    In the above case Job 2 (SPO\_DS\_2) is triggered when Job 1 (SPO\_DS\_1) completes and so on.

    For practical purposes one datasource crawling may be too slow. To increase the number of concurrent jobs use '**MaxConcurrentSharePointJobs**'.

    **Example 'MaxConcurrentSharePointJobs=3':**

    ```bash theme={"dark"}
    SPO_DS_1 Schedule: Every day at 06:00:00\
    SPO_DS_2 Schedule: Trigger job upon completion of SPO_DS_1\
    SPO_DS_3 Schedule: Every day at 06:00:00\
    SPO_DS_4 Schedule: Trigger job upon completion of SPO_DS_3\
    SPO_DS_5 Schedule: Every day at 06:00:00\
    SPO_DS_6 Schedule: Trigger job upon completion of SPO_DS_5
    ```
  </Accordion>

  <Accordion title=" Set up App-Only Auth with Key for SharePoint Online">
    These steps are based on Microsoft’s [Granting Access via Azure AD App-Only](https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azuread).

    ## Create the .cer and .pfx file

    1. Connect a Windows system (any Windows machine is fine).
    2. Save this PowerShell script as **Create-SelfSignedCertificate.ps1**.
       ```bash wrap expandable theme={"dark"}
       #Requires -RunAsAdministrator
       <#
       .SYNOPSIS
       Creates a Self Signed Certificate for use in server to server authentication
       .DESCRIPTION
       .EXAMPLE
       PS C:\> .\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21
       This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key.
       .EXAMPLE
       PS C:\> .\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Password (ConvertTo-SecureString -String "MyPassword" -AsPlainText -Force)
       This will create a new self signed certificate with the common name "CN=MyCert". The password as specified in the Password parameter will be used to protect the private key
       .EXAMPLE
       PS C:\> .\Create-SelfSignedCertificate.ps1 -CommonName "MyCert" -StartDate 2015-11-21 -EndDate 2017-11-21 -Force
       This will create a new self signed certificate with the common name "CN=MyCert". During creation you will be asked to provide a password to protect the private key. If there is already a certificate with the common name you specified, it will be removed first.
       #>
       Param(  
           [Parameter(Mandatory=$true)]
           [string]$CommonName,  
           [Parameter(Mandatory=$true)]
           [DateTime]$StartDate,  
           [Parameter(Mandatory=$true)]
           [DateTime]$EndDate,  
           [Parameter(Mandatory=$false, HelpMessage="Will overwrite existing certificates")]
           [Switch]$Force,  
           [Parameter(Mandatory=$false)]
           [SecureString]$Password
       )  
       # DO NOT MODIFY BELOW  
       function CreateSelfSignedCertificate(){  
           #Remove and existing certificates with the same common name from personal and root stores
           #Need to be very wary of this as could break something
           if($CommonName.ToLower().StartsWith("cn="))
           {
               # Remove CN from common name
               $CommonName = $CommonName.Substring(3)
           }
           $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
           if($certs -ne $null -and $certs.Length -gt 0)
           {
               if($Force)
               {  
                   foreach($c in $certs)
                   {
                       remove-item $c.PSPath
                   }
               } else {
                   Write-Host -ForegroundColor Red "One or more certificates with the same common name (CN=$CommonName) are already located in the local certificate store. Use -Force to remove them";
                   return $false
               }
           }  
           $name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
           $name.Encode("CN=$CommonName", 0)  
           $key = new-object -com "X509Enrollment.CX509PrivateKey.1"
           $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
           $key.KeySpec = 1
           $key.Length = 2048
           $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
           $key.MachineContext = 1
           $key.ExportPolicy = 1 # This is required to allow the private key to be exported
           $key.Create()  
           $serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
           $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") # Server Authentication
           $ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
           $ekuoids.add($serverauthoid)
           $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
           $ekuext.InitializeEncode($ekuoids)  
           $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
           $cert.InitializeFromPrivateKey(2, $key, "")
           $cert.Subject = $name
           $cert.Issuer = $cert.Subject
           $cert.NotBefore = $StartDate
           $cert.NotAfter = $EndDate
           $cert.X509Extensions.Add($ekuext)
           $cert.Encode()  
           $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
           $enrollment.InitializeFromRequest($cert)
           $certdata = $enrollment.CreateRequest(0)
           $enrollment.InstallResponse(2, $certdata, 0, "")
           return $true
       }  
       function ExportPFXFile()
       {
           if($CommonName.ToLower().StartsWith("cn="))
           {
               # Remove CN from common name
               $CommonName = $CommonName.Substring(3)
           }
           if($Password -eq $null)
           {
               $Password = Read-Host -Prompt "Enter Password to protect private key" -AsSecureString
           }
           $cert = Get-ChildItem -Path Cert:\LocalMachine\my | where-object{$_.Subject -eq "CN=$CommonName"}  
           Export-PfxCertificate -Cert $cert -Password $Password -FilePath "$($CommonName).pfx"
           Export-Certificate -Cert $cert -Type CERT -FilePath "$CommonName.cer"
       }  
       function RemoveCertsFromStore()
       {
           # Once the certificates have been exported we can safely remove them from the store
           if($CommonName.ToLower().StartsWith("cn="))
           {
               # Remove CN from common name
               $CommonName = $CommonName.Substring(3)
           }
           $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object{$_.Subject -eq "CN=$CommonName"}
           foreach($c in $certs)
           {
               remove-item $c.PSPath
           }
       }  
       if(CreateSelfSignedCertificate)
       {
           ExportPFXFile
           RemoveCertsFromStore
       }
       ```
    3. Open a Command prompt or PowerShell: Run as Administrator
    4. Run the below script to create the .pfx and .cer files needed for the next steps, where:
       1. `StartDate`: Current Date
       2. `EndDate`: Current Date + 2 years
       3. `CommonName`: Name given to the .cer and .pfx files, such as `YourFileName`

    ```bash theme={"dark"}
    \Create-SelfSignedCertificate.ps1 -CommonName "YourFileName" -StartDate YYYY-MM-DD -EndDate YYYY-MM-DD
    ```

    At running the command, a password will be requested to protect the private key. **YourFileName.pfx** and **YourFileName.cer** files will be created.

    ## Register a new App

    * Go to the [Azure Portal](https://portal.azure.com/) , select the **Azure Active Directory** section, and choose the option **App registrations**.
    * Register a new application: **App Registrations → New Registration** [https://portal.azure.com/#blade/Microsoft\_AAD\_IAM/ActiveDirectoryMenuBlade/RegisteredApps](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps)

    <Check>Once the application has been created, copy the **Application (client) ID** as you’ll need to configure the datasource.</Check>

    ### Grant permission to App

    * From **API permissions** in the left menu bar, click on the **Add a permission** button. Choose the permissions that you will grant to this application.
      * Choose **Sharepoint** permissions, and select the permissions needed (**Application → Sites.FullControl.All**)
    * Click on the **Grant admin consent for OrganizationName** button and confirm the action by clicking on the **Yes** button that appears at the top.
    * From **Certificates & Secrets** in the left menu, upload the Certificate file (YourFIleName.cer) created earlier:

    ## Obtain the base64 code from the .pfx file

    It can be obtained in two ways

    1. From Command Line (Linux)
       * Convert the .pfx to .pc12
       ```bash theme={"dark"}
       keytool -importkeystore -srckeystore YourFileName.pfx -srcstoretype pkcs12 -destkeystore yourcert.p12 -deststoretype pkcs12
       ```
       * Convert the .pc12 to base64
       ```bash theme={"dark"}
       base64 -i yourcert.p12 > base64.txt
       ```
       * Open the .txt file and copy the value generated, you will need it to configure the datasource config

    2. From PowerShell
       * From PowerShell, run the following commands:
       ```bash theme={"dark"}
       $fileContentBytes = get-content '.\YourFileName.pfx' -Encoding Byte
       [System.Convert]::ToBase64String($fileContentBytes) | Out-File 'pfx-encoded-bytes.txt'
       ```
       * Open the .txt file and copy the value generated, you will need it to configure the datasource config

    ## Renew the Certificate

    When the certificate expires, the crawl will fail with the following error:

    ```bash theme={"dark"}
    Client assertion contains an invalid signature. [Reason - The key used is expired
    1AuthenticationException: {"error_description":"AADSTS700027: Client assertion contains an invalid signature. [Reason - The key used is expired., Thumbprint of key used by client:"...]}
    ```

    The .cer and .pfx need to be renewed. Follow these steps:

    * Execute the script from '' to get a new .cer and .pfx files
    * Go to the [Azure Portal](https://portal.azure.com/), select the **Azure Active Directory** section, choose the option **App registrations**, and open the Application from where the certificate expired.
    * From **Certificates & Secrets’in** the left menu bar, remove the older certificate, and upload the new one
    * Obtain the base64 from the renewed .pfx file

    ## Set up App-only Authentication With Private Key into Sharepoint v2 plugin

    * Client ID, and Base64 from the .pfx file, and password for the private key, must be set into **Azure AD Client ID**, **AZURE AD PKCS12 BASE64 KEYSTORE**, and **AZURE AD PKCS12 KEYSTORE PASSWORD** properties respectively
    * Set the appropriate tenant into **Azure AD Tenant** property, for example, `lucidworksfusion.onmicrosoft.com`
  </Accordion>

  <Accordion title="Validate Your SharePoint Online Crawl Account Permissions Using PowerShell">
    ## Overview of procedure

    **How to set up and validate SharePoint Online crawl account permissions:**

    1. [Authenticate to SharePoint Online](#authenticate-to-sharepoint-online).
    2. [Get the FedAuth and rtFa cookie values](#get-the-fedauth-and-rtfa-cookie-values).
    3. [Add your information to the PowerShell script](#add-your-information-to-the-powershell-script).
    4. [Add your URL and DigestValue](#add-your-url-and-digestvalue).

    ## Authenticate to SharePoint Online

    Authenticate to SharePoint Online as the service account user.

    ## Get the FedAuth and rtFa cookie values

    Open up your Debugging Tools (such as DevTools from Chrome) and copy the `FedAuth` and `rtFa` cookies from session.

    ## Add your information to the PowerShell script

    Enter your site and these two cookies into this PowerShell script:

    ```bash wrap theme={"dark"}
    # change these 3 variables to match your environment
    $sharepointUrl = "https://YourSharePointURL.com"

    $fedAuthCookieValue = "EnterYourFedAuthCookieValueHere"

    $rtFaValue = "EnterYourRtfaCookieValueHere"

    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Content-Type", "text/xml")
    $headers.Add("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetUpdatedFormDigestInformation")
    $headers.Add("X-RequestForceAuthentication", "true")
    $headers.Add("Cookie", "FedAuth=$fedAuthCookieValue;rtFa=$rtFaValue")

    $body = "<?xml version=`"1.0`" encoding=`"utf-8`"?>`n<soap:Envelope xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`" xmlns:xsd=`"http://www.w3.org/2001/XMLSchema`" xmlns:soap=`"http://schemas.xmlsoap.org/soap/envelope/`">`n  <soap:Body>`n    <GetUpdatedFormDigestInformation xmlns=`"http://schemas.microsoft.com/sharepoint/soap/`" />`n  </soap:Body>`n</soap:Envelope>"

    $response = Invoke-RestMethod "$sharepointUrl/_vti_bin/sites.asmx" -Method 'POST' -Headers $headers -Body $body
    Write-Host "$response"
    ```

    The response will resemble:

    ```xml wrap theme={"dark"}
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <soap:Body>
            <GetUpdatedFormDigestInformationResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
                <GetUpdatedFormDigestInformationResult>
                      **<DigestValue>YourDigestValueWithTimestamp</DigestValue>**
                      <TimeoutSeconds>1800</TimeoutSeconds>
                    <WebFullUrl>https://lucidworksfusiondev.sharepoint.com/sites/ndd2</WebFullUrl>
                    <LibraryVersion>16.0.19527.12083</LibraryVersion>
                    <SupportedSchemaVersions>14.0.0.0,15.0.0.0</SupportedSchemaVersions>
                </GetUpdatedFormDigestInformationResult>
            </GetUpdatedFormDigestInformationResponse>
        </soap:Body>
    </soap:Envelope>
    ```

    ## Add your URL and DigestValue

    Copy the `DigestValue` from this response into the PowerShell script below. Also change the SharePoint URL to match your environment.

    ```bash wrap  theme={"dark"}
    # change these 2 variables to match your environment
    $sharepointUrl = "https://YourSharePointURL.com"
    $digestValue = "YourDigestValueWithTimestamp"

    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Content-Type", "text/xml")
    $headers.Add("X-RequestForceAuthentication", "true")
    $headers.Add("X-RequestDigest", "$digestValue")

    $body = "<Request AddExpandoFieldTypeSuffix=`"true`" SchemaVersion=`"14.0.0.0`" LibraryVersion=`"16.0.0.0`" ApplicationName=`".NET Library`" xmlns=`"http://schemas.microsoft.com/sharepoint/clientquery/2009`"><Actions><ObjectPath Id=`"2`" ObjectPathId=`"1`"/><ObjectPath Id=`"4`" ObjectPathId=`"3`"/><Query Id=`"5`" ObjectPathId=`"3`"><Query SelectAllProperties=`"false`"><Properties><Property Name=`"Webs`" SelectAll=`"true`"><Query SelectAllProperties=`"false`"><Properties/></Query></Property><Property Name=`"Title`" ScalarProperty=`"true`"/><Property Name=`"ServerRelativeUrl`" ScalarProperty=`"true`"/><Property Name=`"RoleDefinitions`" SelectAll=`"true`"><Query SelectAllProperties=`"false`"><Properties/></Query></Property><Property Name=`"RoleAssignments`" SelectAll=`"true`"><Query SelectAllProperties=`"false`"><Properties/></Query></Property><Property Name=`"HasUniqueRoleAssignments`" ScalarProperty=`"true`"/><Property Name=`"Description`" ScalarProperty=`"true`"/><Property Name=`"Id`" ScalarProperty=`"true`"/><Property Name=`"LastItemModifiedDate`" ScalarProperty=`"true`"/></Properties></Query></Query></Actions><ObjectPaths><StaticProperty Id=`"1`" TypeId=`"{3747adcd-a3c3-41b9-bfab-4a64dd2f1e0a}`" Name=`"Current`"/><Property Id=`"3`" ParentId=`"1`" Name=`"Web`"/></ObjectPaths></Request>"

    $response = Invoke-RestMethod "$sharepointUrl/_vti_bin/client.svc/ProcessQuery" -Method 'POST' -Headers $headers -Body $body
    Write-Host "$response"
    ```

    If permissions are ***incorrect***, you will get an error message.

    ```json wrap theme={"dark"}
    [
        {
            "SchemaVersion": "14.0.0.0",
            "LibraryVersion": "16.0.19527.12083",
            "ErrorInfo": {
                "ErrorMessage": "Access denied. You do not have permission to perform this action or access this resource.",
                "ErrorValue": null,
                "TraceCorrelationId": "640d309f-b0f7-b000-8100-49826f3674cb",
                "ErrorCode": -2147024891,
                "ErrorTypeName": "System.UnauthorizedAccessException"
            },
            "TraceCorrelationId": "640d309f-b0f7-b000-8100-49826f3674cb"
        }
    ]
    ```

    If permissions are **correct**, you will get a response that resembles:

    ```json wrap expandable theme={"dark"}
    [
        {
            "SchemaVersion": "14.0.0.0",
            "LibraryVersion": "16.0.19527.12083",
            "ErrorInfo": null,
            "TraceCorrelationId": "e70c309f-3097-b000-4931-8fe95320fdb0"
        },
        2,
        {
            "IsNull": false
        },
        4,
        {
            "IsNull": false
        },
        5,
        {
            "_ObjectType_": "SP.Web",
            "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a",
            "Webs": {
                "_ObjectType_": "SP.WebCollection",
                "_Child_Items_": []
            },
            "Title": "NddTest",
            "ServerRelativeUrl": "/sites/ndd2",
            "RoleDefinitions": {
                "_ObjectType_": "SP.RoleDefinitionCollection",
                "_Child_Items_": [
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741829",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 2147483647,
                            "Low": 4294967295
                        },
                        "Description": "Has full control.",
                        "Hidden": false,
                        "Id": 1073741829,
                        "Name": "Full Control",
                        "Order": 1,
                        "RoleTypeKind": 5
                    },
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741828",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 432,
                            "Low": 1012866047
                        },
                        "Description": "Can view, add, update, delete, approve, and customize.",
                        "Hidden": false,
                        "Id": 1073741828,
                        "Name": "Design",
                        "Order": 32,
                        "RoleTypeKind": 4
                    },
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741830",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 432,
                            "Low": 1011030767
                        },
                        "Description": "Can add, edit and delete lists; can view, add, update and delete list items and documents.",
                        "Hidden": false,
                        "Id": 1073741830,
                        "Name": "Edit",
                        "Order": 48,
                        "RoleTypeKind": 6
                    },
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741827",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 432,
                            "Low": 1011028719
                        },
                        "Description": "Can view, add, update, and delete list items and documents.",
                        "Hidden": false,
                        "Id": 1073741827,
                        "Name": "Contribute",
                        "Order": 64,
                        "RoleTypeKind": 3
                    },
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741826",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 176,
                            "Low": 138612833
                        },
                        "Description": "Can view pages and list items and download documents.",
                        "Hidden": false,
                        "Id": 1073741826,
                        "Name": "Read",
                        "Order": 128,
                        "RoleTypeKind": 2
                    },
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741825",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 48,
                            "Low": 134287360
                        },
                        "Description": "Can view specific lists, document libraries, list items, folders, or documents when given permissions.",
                        "Hidden": true,
                        "Id": 1073741825,
                        "Name": "Limited Access",
                        "Order": 160,
                        "RoleTypeKind": 1
                    },
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741924",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 176,
                            "Low": 138612801
                        },
                        "Description": "Can view pages, list items, and documents. Document types with server-side file handlers can be viewed in the browser but not downloaded.",
                        "Hidden": false,
                        "Id": 1073741924,
                        "Name": "View Only",
                        "Order": 2147483647,
                        "RoleTypeKind": 0
                    },
                    {
                        "_ObjectType_": "SP.RoleDefinition",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:rd:1073741925",
                        "BasePermissions": {
                            "_ObjectType_": "SP.BasePermissions",
                            "High": 1073741856,
                            "Low": 203624545
                        },
                        "Description": "",
                        "Hidden": false,
                        "Id": 1073741925,
                        "Name": "LW Fusion",
                        "Order": 2147483647,
                        "RoleTypeKind": 0
                    }
                ]
            },
            "RoleAssignments": {
                "_ObjectType_": "SP.RoleAssignmentCollection",
                "_Child_Items_": [
                    {
                        "_ObjectType_": "SP.RoleAssignment",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:ra:3",
                        "PrincipalId": 3
                    },
                    {
                        "_ObjectType_": "SP.RoleAssignment",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:ra:6",
                        "PrincipalId": 6
                    },
                    {
                        "_ObjectType_": "SP.RoleAssignment",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:ra:7",
                        "PrincipalId": 7
                    },
                    {
                        "_ObjectType_": "SP.RoleAssignment",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:ra:8",
                        "PrincipalId": 8
                    },
                    {
                        "_ObjectType_": "SP.RoleAssignment",
                        "_ObjectIdentity_": "e70c309f-3097-b000-4931-8fe95320fdb0|740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:d714bad3-ef71-4f83-86b6-25405106b719:web:ab8c2f1e-c518-4b2a-a89f-c6404b97a85a:ra:14",
                        "PrincipalId": 14
                    }
                ]
            },
            "HasUniqueRoleAssignments": true,
            "Description": "",
            "Id": "/Guid(ab8c2f1e-c518-4b2a-a89f-c6404b97a85a)/",
            "LastItemModifiedDate": "/Date(1580251756000)/"
        }
    ]
    ```
  </Accordion>
</AccordionGroup>

## Configuration

<Tip>
  When entering configuration values in the UI, use *unescaped* characters, such as `\t` for the tab character. When entering configuration values in the API, use *escaped* characters, such as `\\t` for the tab character.
</Tip>

<SchemaParamFields schema={schema} />
