🚀 Simplify your work by integrating Haufe Copilot via API
Guides

OAuth: Let Your Users Log In with Haufe

Your users log in with their Haufe account, and your product calls Copilot via API with their own access token.

You like to integrate a Haufe copilot into your own product. Your users have a Haufe account. They log in with that account inside your product. Your backend then calls Copilot via API with the access token of the user. The content package of the user decides which content the copilot can use for the answer.

This page describes how you get your OAuth client, how you run the login flow, and how you send the token. If your application calls the API in its own name, use an API key instead.

How It Works

  1. Your backend redirects the user to the Haufe login.
  2. The user logs in with their Haufe account and returns to your redirect URI with an authorization code.
  3. Your backend exchanges the code for an access token and a refresh token.
  4. Your backend sends the access token as a bearer token to Copilot via API.
  5. The API checks the signature and the expiry of the token and the subscription of your client.
  6. The API reads the content package of the user from the token, then answers the request.

The flow is the standard OAuth 2.0 authorization code flow with PKCE. The browser of the user never sees a token. Keep the client secret and all tokens on your backend.

Get Your Client ID and Client Secret

Send your redirect URI to Haufe

The redirect URI is the endpoint of your backend that receives the authorization code, for example https://app.example.com/auth/callback. Use an https URI in production. For local tests, http URIs are accepted for localhost and loopback addresses only, for example http://localhost:9999/callback. We recommend a separate application for local tests. Then the client secret of your production application stays on your backend. Your Haufe contact person creates the OAuth application with this URI and assigns it to your account.

Read your credentials in the portal

Open the application in the Developer Portal. The settings show the client ID and the client secret. Renew client secret creates a new secret. The old secret stops working immediately.

Manage your redirect URIs in the portal

You can add and remove redirect URIs in the application settings. Save the application after the change. The client ID and the client secret stay the same after a save.

warning

Treat the client secret like a password. Store it on your backend only. Never ship it in a browser or mobile app.

Run the Login Flow

The Haufe login is an OpenID Connect provider. Use an OpenID Connect library for your platform and configure it with these values. Most libraries read the endpoints from the discovery document at https://iam.auth.haufe.io/.well-known/openid-configuration.

SettingValue
Issuerhttps://iam.auth.haufe.io
Authorization endpointhttps://iam.auth.haufe.io/oauth/v2/authorize
Token endpointhttps://iam.auth.haufe.io/oauth/v2/token
Grant typeauthorization_code with PKCE (S256)
Client authenticationclient_secret_basic
Scopesopenid profile email offline_access
info

The scope offline_access gives you a refresh token. Without it, the user must log in again when the access token expires.

Redirect the user to the authorization endpoint

Authorization request
https://iam.auth.haufe.io/oauth/v2/authorize
  ?response_type=code
  &client_id=<CLIENT_ID>
  &redirect_uri=https://app.example.com/auth/callback
  &scope=openid%20profile%20email%20offline_access
  &state=<RANDOM_STATE>
  &code_challenge=<CODE_CHALLENGE>
  &code_challenge_method=S256

The user logs in with their Haufe account. The login then redirects the browser to your redirect URI with the query parameters code and state. Check that state matches the value you sent.

Exchange the code for tokens

Token request
curl --request POST \
  --url https://iam.auth.haufe.io/oauth/v2/token \
  --user '<CLIENT_ID>:<CLIENT_SECRET>' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'grant_type=authorization_code' \
  --data 'code=<CODE>' \
  --data 'redirect_uri=https://app.example.com/auth/callback' \
  --data 'code_verifier=<CODE_VERIFIER>'
Token response (example)
{
  "access_token": "<ACCESS_TOKEN>",
  "token_type": "Bearer",
  "expires_in": 43199,
  "refresh_token": "<REFRESH_TOKEN>",
  "id_token": "<ID_TOKEN>"
}
  • access_token is the token you send to Copilot via API. It is a JSON Web Token. Send it as it is and do not build logic on its content.
  • expires_in is the lifetime of the access token in seconds. Refresh the token before it expires.
  • id_token is a JSON Web Token with the identity of the user. Use it for your own session, not for the API.

Refresh the access token

Refresh request
curl --request POST \
  --url https://iam.auth.haufe.io/oauth/v2/token \
  --user '<CLIENT_ID>:<CLIENT_SECRET>' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'grant_type=refresh_token' \
  --data 'refresh_token=<REFRESH_TOKEN>'

The response has the same shape as the token response. If the refresh fails, send the user through the login again.

Call the API with the Access Token

Send the access token in the Authorization header. Do not send an api-key header.

List available assistants
curl --request GET \
  --url https://api.haufe.ai/agents/v1/assistants \
  --header 'Authorization: Bearer <ACCESS_TOKEN>'

All endpoints in the Quickstart and the API Reference work the same way. The examples there show the api-key header. Replace it with the Authorization header.

info

With OAuth user tokens, the content package of the user comes from the token. The request metadata meta_data.user_data.licence has no effect. Do not send it.

Error Codes

HTTP StatusResponseCause
401{"message": "Unauthorized", "http_status_code": 401}The request has no Authorization header, the access token is expired or not valid, or your client has no active subscription.
403{"error_code": "assistant_not_licensed", "detail": "The access token has no licensed product for this assistant"}The user has no license for a product of this assistant. GET /v1/assistants lists only the assistants the user can use.
403{"error_code": "thread_requires_access_token", "detail": "The thread was created with an access token. Send an access token to run it"}The run has no access token, but the thread was created with one. Send the Authorization header on every run of this thread.
404{"error_code": "thread_not_found", "detail": "Thread not found"}The run has the access token of a different user than the user that created the thread. Run the thread with the token of that user.
422{"error_code": "user_id_conflicts_with_token", "detail": "Do not send a user_id with an access token. The token gives the user"}The request body has a user_id. Remove user_id. The API gets the user from the token.
422{"error_code": "user_tenant_id_conflicts_with_token", "detail": "Do not send a user_tenant_id with an access token. The token gives the tenant"}The request body has a user_tenant_id. Remove user_tenant_id. The API gets the tenant from the token.

If you get a 401 with a token that worked before, refresh the token and retry once. If the refresh fails, send the user through the login again. If every token of your client gets a 401, the subscription of your application is missing or not active. Contact your Haufe contact person.

Next Steps

On this page