Skip to content

Sharepoint certificate authorization does not work #71

Description

@valpo

I am using the oikb container (latest), and try to connect to sharepoint online:

docker compose exec -it oikb sh
# env | grep SHAREPOINT
SHAREPOINT_CLIENT_ID=***
SHAREPOINT_CERTIFICATE_PATH=/certs/oikb-sharepoint.pem
SHAREPOINT_TENANT_ID=***

But the login does not work:

docker compose logs -f oikb
....
oikb  | {"ts": "2026-07-01T06:12:21Z", "level": "ERROR", "logger": "oikb.daemon", "msg": "Sync failed for sharepoint:***.sharepoint.com/sites/**localPath***: Client error '401 Unauthorized' for url 'https://login.microsoftonline.com/***SHAREPOINT_TENANT_ID***/oauth2/v2.0/token'\nFor more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401"}

I am not an expert in this area, so I've googled some code to verify the setup:

import os, time, uuid, jwt, requests, base64, hashlib
from cryptography import x509
from cryptography.hazmat.backends import default_backend

tenant = os.environ["SHAREPOINT_TENANT_ID"]
client_id = os.environ["SHAREPOINT_CLIENT_ID"]
pem_path = os.environ["SHAREPOINT_CERTIFICATE_PATH"]

pem = open(pem_path, "rb").read()
private_key = pem.decode()

cert_pem = pem[pem.find(b"-----BEGIN CERTIFICATE-----"):]
cert = x509.load_pem_x509_certificate(cert_pem, default_backend())
der = cert.public_bytes(encoding=__import__("cryptography.hazmat.primitives.serialization").hazmat.primitives.serialization.Encoding.DER)

# SHA-1 thumbprint für x5t, base64url ohne Padding
x5t = base64.urlsafe_b64encode(hashlib.sha1(der).digest()).decode().rstrip("=")

now = int(time.time())
token_url = f"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token"

payload = {
    "aud": token_url,
    "iss": client_id,
    "sub": client_id,
    "jti": str(uuid.uuid4()),
    "nbf": now,
    "exp": now + 600,
}

assertion = jwt.encode(
    payload,
    private_key,
    algorithm="RS256",
    headers={"x5t": x5t}
)

r = requests.post(token_url, data={
    "client_id": client_id,
    "scope": "https://graph.microsoft.com/.default",
    "grant_type": "client_credentials",
    "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
    "client_assertion": assertion,
})

print("STATUS:", r.status_code)
print(r.text)

If I run this code inside the oikb-container, it seems to work:

docker compose run --rm --entrypoint sh oikb -lc 'pip install requests && python /certs/test-auth1.py'
...
STATUS: 200
{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":"***"}

I looks like my setup is fine.

The main difference between the code above and sharepoint.py are these lines:

 # Load certificate to extract thumbprint.
    cert = x509.load_pem_x509_certificate(pem_data)
    thumbprint = cert.fingerprint(cert.signature_hash_algorithm or x509.hashes.SHA256())
    x5t = base64.urlsafe_b64encode(thumbprint).rstrip(b"=").decode("ascii")

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions