Skip to content

DataPlatform as Identity Provider

The DataPlatform can act as the Identity Provider (IdP) for applications built by OEM and distributor customers, letting them build their own branded web or mobile applications with secure sign-in via the DataPortal and access to the REST API limited to the existing DataPortal permission sets of the signed-in user.

Note

DataPlatform as Identity Provider is available for qualified OEM and distributor customers. It is configured by Proemion for each customer. There is no self-service option to register an application in the DataPortal.
To assess fit and start onboarding, make a request via the Sales Team Contact Form.

Overview

Such a custom application is customer-owned, registered with Proemion, and connected to the DataPlatform. End users of the application sign in through a Proemion-managed SSO flow, and the application calls the REST API on their behalf with scoped Permission Sets.

This is different from an API Client, which is intended for machine-to-machine integrations without an individual end user, such as scripts or ERP integrations.

The feature replaces the legacy OAuth 2.0 token endpoint, which does not support refresh tokens and requires users to log in again every 4 hours.

Key capabilities:

  • User sign-in via Proemion SSO: End users authenticate through a Proemion-managed SSO flow. The OEM or distributor controls the branding and user experience of their own application. No customer-operated identity system (for example Azure AD) is required.
  • User-centric API access: API access is scoped to the permissions of the signed-in DataPortal user, including support for Multi-Factor Authentication.
  • AI and automation ready: Simple, one-purpose apps, such as dashboards, alerting tools, or internal utilities, can be built using AI app builders or automation tools, leveraging DataPlatform as Identity Provider to securely access Proemion APIs.
  • Governed onboarding: Proemion configures each application, including redirect URIs, scopes, and environments.

When to Use DataPlatform as Identity Provider

DataPlatform as Identity Provider is suited for OEMs and distributors that want to offer a branded, user-facing application, such as a dealer portal, fleet app, or service tool, based on DataPlatform data.

It is not suited for:

  • Purely machine-to-machine integrations without an end user. Create an API Client instead.
  • Customers with an existing enterprise SSO system who want to integrate it directly with DataPlatform. A direct integration with the customer's own identity system remains the preferred model in this case.
  • Data sovereignty or DataLake use cases. Use the DataPump Service instead.
  • Customers who want a ready-made app without building and maintaining their own. Use the Machine Companion App instead, see the Machine Companion App Manual.

Setup

Contact your Proemion sales representative with the following information:

  1. Full customer name
  2. Purpose of the application
  3. Name of the application
  4. Redirect URL the user should be sent to after authentication
  5. Whether a Whitelabel setup exists for your organization. A Whitelabel setup is recommended.

Proemion configures the application and provides:

  • A client ID
  • The SSO configuration endpoint, available at .well-known/openid-configuration on your DataPortal domain, for example https://dataportal.proemion.com/.well-known/openid-configuration

Use the client ID with a PKCE-based OAuth flow to sign in a user and call the REST API on their behalf.

Python example: PKCE OAuth flow

The following example requests a token and calls the /me endpoint to confirm the setup:

import base64
import hashlib
import os
import threading
import webbrowser
import json
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs

import requests
from requests_oauthlib import OAuth2Session

# Replace with your DataPortal domain (use your Whitelabel domain if applicable)
BASE_URL = "REPLACE_ME"

CLIENT_ID = "REPLACE_ME"

# Replace with the redirect URI configured for your application
REDIRECT_URI = "http://localhost:8080/callback"

SCOPES = ["openid", "profile", "email"]

# Replace with the current API version, see the versioning guide:
# https://docs.proemion.com/api/#versioning
API_VERSION = "REPLACE_ME"

WELLKNOWN_URL = f"{BASE_URL}/.well-known/openid-configuration"
ME_ENDPOINT = f"{BASE_URL}/api/{API_VERSION}/me"

config = requests.get(WELLKNOWN_URL).json()
AUTHORIZATION_ENDPOINT = config["authorization_endpoint"]
TOKEN_ENDPOINT = config["token_endpoint"]

def generate_pkce():
    verifier = base64.urlsafe_b64encode(os.urandom(40)).decode().rstrip("=")
    challenge = base64.urlsafe_b64encode(
        hashlib.sha256(verifier.encode()).digest()
    ).decode().rstrip("=")
    return verifier, challenge

code_verifier, code_challenge = generate_pkce()

authorization_code = None

class CallbackHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        global authorization_code

        parsed = urlparse(self.path)
        if parsed.path != "/callback":
            self.send_response(404)
            self.end_headers()
            return

        query = parse_qs(parsed.query)
        authorization_code = query.get("code", [None])[0]

        if not authorization_code:
            self.send_response(400)
            self.end_headers()
            self.wfile.write(b"Missing authorization code")
            return

        try:
            token = oauth.fetch_token(
                TOKEN_ENDPOINT,
                code=authorization_code,
                client_id=CLIENT_ID,
                code_verifier=code_verifier,
                include_client_id=True,
            )
            access_token = token["access_token"]

            response = requests.get(
                ME_ENDPOINT,
                headers={
                    "Authorization": f"Bearer {access_token}",
                    "Accept": "application/json",
                },
            )
            response.raise_for_status()
            me_data = response.json()

            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps(me_data, indent=2).encode())

        except Exception as e:
            self.send_response(500)
            self.end_headers()
            self.wfile.write(str(e).encode())

    def log_message(self, format, *args):
        return

server = HTTPServer(("localhost", 8080), CallbackHandler)
threading.Thread(target=server.serve_forever, daemon=True).start()

oauth = OAuth2Session(client_id=CLIENT_ID, redirect_uri=REDIRECT_URI, scope=SCOPES)
auth_url, state = oauth.authorization_url(
    AUTHORIZATION_ENDPOINT,
    code_challenge=code_challenge,
    code_challenge_method="S256",
)

webbrowser.open(auth_url)

try:
    while True:
        pass
except KeyboardInterrupt:
    server.shutdown()