# Upgrade Your Authentication Flow to OAuth 2.0

> Step-by-step guide to upgrade Kiteworks API integrations from deprecated Signature or User Credentials flows to Authorization Code (OAuth 2.0) or JWT Assertion.

Upgrade Guides

# Upgrade Your Authentication Flow to OAuth 2.0

This guide helps you upgrade your Kiteworks API integration from a deprecated authentication flow — Signature or User Credentials — to a supported OAuth 2.0 flow. To upgrade, update the client registration in Admin UI and update your token-acquisition code.

## Prerequisites

1

Admin access to Kiteworks Admin UI

You must have permission to edit client application settings under **Application Setup → Apps and Plugins**.

2

Your existing `client_id` and `client_secret`

These carry over to the new flow unchanged. You only need to regenerate the secret if it was previously exposed.

3

For JWT Assertion: an RSA key pair (optional)

You can generate a key pair directly in Admin UI or upload your own PEM-encoded public key. Only required if you are upgrading to JWT Assertion.

## Who Is Affected

This guide applies to integrations using the Signature flow (HMAC-based) or the User Credentials flow (`grant_type=password`).

> To check which flow your client uses, see [Check Your API Version](upgrade-check-version.html) or go to **Admin UI → Application Setup → Apps and Plugins → API → [your client]**, where you can see the registered flow.

## Which Flow Should I Use?

Choose your target flow based on how your application operates:

| Use Case | Recommended Flow | Reason |
|---|---|---|
| User logs in via browser / user-initiated workflow | Authorization Code Flow (shown as **Connect (Authorization Code)** in Admin UI) | User authenticates in browser; your application never handles their credentials |
| Automated / server-to-server (machine-to-machine) | **JSON Web Token** (**JWT**) Assertion | Requires no user interaction; secure for trusted server environments |

> JWT Assertion allows impersonation of Kiteworks users. It must only be used by clients operating in secure, trusted server environments. It is not appropriate for publicly accessible clients.

## Step 1 — Identify Your Current Flow

### Signature Flow

The Signature flow uses a time-based **Hash-based Message Authentication Code** (**HMAC**) signature computed from `client_id` + `client_secret` + `timestamp`. No user account is associated; activity does not appear in audit logs. Kiteworks removed the Signature flow from Admin UI registration in version 9.1.

To identify: In **Admin UI → Application Setup → Apps and Plugins → API**, the client's registered flow shows as "Signature." In your code, look for HMAC signature construction — typically a string like:

python Copy

```python
import hmac, hashlib, time

timestamp = str(int(time.time()))
message   = client_id + client_secret + timestamp
sig       = hmac.new(client_secret.encode(), message.encode(), hashlib.sha256).hexdigest()
```

### User Credentials Flow

The User Credentials flow (OAuth 2.0 Resource Owner Password Credential) submits a username and password directly in the token request body. Kiteworks removed the User Credentials flow from Admin UI in version 9.0.

To identify: Look for `grant_type=password` in token requests:

bash Copy

```bash
curl -s -X POST "https://your-instance.kiteworks.com/oauth/token" \
  -d "grant_type=password&username=user@example.com&password=SECRET&client_id=MY_APP&client_secret=MY_SECRET"
```

## Step 2 — Register the New Flow in Admin UI

Before changing your code, update the client's registered flow in Admin UI. Steps 1–4 apply to both flows; step 5 depends on which flow you're upgrading to.

1. **Open the API clients settings.** Navigate to **Admin UI → Application Setup → Apps and Plugins → API**.
2. **Select your client application.** Choose the application your integration uses.
3. **Open the Flows tab.** Go to **Settings → Flows**.
4. **Select the new flow.** Change the flow to **Connect (Authorization Code)** or **JWT Assertion** depending on your use case.

**Step 5 — If upgrading to Authorization Code Flow:**

5. **Configure the Redirect URI.** Set the **Redirect URI** to the HTTPS callback URL your application handles after login — for example, `https://your-app.example.com/callback`. Your application must serve an endpoint at this URL to receive the authorization code.

**Step 5 — If upgrading to JWT Assertion:**

5. **Configure the RSA key pair.** Upload or generate an RSA key pair; note the **UID attribute** (determines the user to impersonate — typically `email`).

Flows panel in Admin UI — select Authorization Code or JWT to replace the deprecated flow.

## Step 3A — Implement Authorization Code Flow

To implement the Authorization Code Flow (RFC 6749 §4.1), complete the following steps. The user authenticates at the Kiteworks login page; your application exchanges the returned authorization code for an access token.

1. **Redirect the user to the authorization endpoint.** Start the flow with the required `client_id`, `redirect_uri`, `response_type=code`, and `state` parameters.
2. **Receive the authorization code.** After login, Kiteworks redirects to your `redirect_uri` with a `code` and `state` parameter.
3. **Exchange the code for tokens.** Verify the `state` parameter matches the value you set when starting the flow (**Cross-Site Request Forgery** (**CSRF**) protection), then POST to the token endpoint to exchange the code for tokens.
4. **Attach required headers to all API requests.** Use `Authorization: Bearer <access_token>` and `X-Accellion-Version: 28` on all API requests.
5. **Refresh tokens before expiry.** Use the refresh token to obtain new access tokens before they expire.

Endpoints:

- **Authorization endpoint:** `GET {KW_BASE_URL}/oauth/authorize`
- **Token endpoint:** `POST {KW_BASE_URL}/oauth/token`

Token exchange:

cURL Python

exchange-code.sh Copy

```bash
# Exchange authorization code for tokens
curl -s -X POST "https://your-instance.kiteworks.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://your-app.example.com/callback" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
```

exchange_code.py Copy

```python
import requests

# AUTHORIZATION_CODE comes from the ?code= query parameter in the redirect
# In Flask:  AUTHORIZATION_CODE = request.args.get("code")
# In Django: AUTHORIZATION_CODE = request.GET.get("code")
AUTHORIZATION_CODE = "YOUR_AUTHORIZATION_CODE"  # replace with actual value from redirect

token_url = "https://your-instance.kiteworks.com/oauth/token"
data = {
    "grant_type":    "authorization_code",
    "code":          AUTHORIZATION_CODE,
    "redirect_uri":  "https://your-app.example.com/callback",
    "client_id":     CLIENT_ID,
    "client_secret": CLIENT_SECRET,
}
resp  = requests.post(token_url, data=data)
tokens = resp.json()
access_token  = tokens["access_token"]
refresh_token = tokens["refresh_token"]
```

Refresh token:

cURL Python

refresh-token.sh Copy

```bash
curl -s -X POST "https://your-instance.kiteworks.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=REFRESH_TOKEN" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
```

refresh_token.py Copy

```python
import requests

token_url = "https://your-instance.kiteworks.com/oauth/token"
data = {
    "grant_type":    "refresh_token",
    "refresh_token": current_refresh_token,   # the token stored from the previous response
    "client_id":     CLIENT_ID,
    "client_secret": CLIENT_SECRET,
}
resp = requests.post(token_url, data=data)
tokens = resp.json()
new_access_token  = tokens["access_token"]
new_refresh_token = tokens["refresh_token"]   # replace stored token with this value
```

For a complete Python implementation including the browser redirect and callback server, see [Authentication → Authorization Code flow](authentication.html#authorization-code).

## Step 3B — Implement JWT Assertion Flow

The JWT Assertion flow is the OAuth 2.0 JWT Bearer token grant (RFC 7523). It requires no user interaction — your application constructs a signed JWT and exchanges it for an access token.

| Claim | Description | Example |
|---|---|---|
| `iss` | Issuer — your `client_id` | `my_app_client_id` |
| `sub` | Subject — email of the Kiteworks user to impersonate | `user@example.com` |
| `aud` | Audience — the Kiteworks token endpoint URL | `https://kw.example.com/oauth/token` |
| `iat` | Issued-at time (Unix timestamp) | `1712768400` |
| `exp` | Expiration time (max 5 minutes from `iat`) | `1712768700` |
| `jti` | Unique JWT ID (prevents replay attacks) | `a3f8c1d2-...` |

Signing algorithm: RS256 (RSA with SHA-256). Token endpoint: `POST {KW_BASE_URL}/oauth/token`

Construct and exchange JWT:

cURL Python

jwt-assertion.sh Copy

```bash
# Generate a signed JWT first (e.g. with step CLI or openssl), then exchange:
curl -s -X POST "https://your-instance.kiteworks.com/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
  -d "assertion=YOUR_SIGNED_JWT" \
  -d "client_id=YOUR_CLIENT_ID"
```

jwt_assertion.py Copy

```python
# pip install PyJWT requests
import time, uuid, jwt, requests

# Load the RSA private key (PEM format) registered in Admin UI → Apps and Plugins → Flows
PRIVATE_KEY_PEM = open("private_key.pem").read()
CLIENT_ID       = "your_client_id"
KW_BASE_URL     = "https://your-instance.kiteworks.com"
USER_EMAIL      = "user@example.com"

now = int(time.time())
payload = {
    "iss": CLIENT_ID,
    "sub": USER_EMAIL,
    "aud": f"{KW_BASE_URL}/oauth/token",
    "iat": now,
    "exp": now + 300,   # 5 minutes
    "jti": str(uuid.uuid4()),
}
assertion = jwt.encode(payload, PRIVATE_KEY_PEM, algorithm="RS256")

resp = requests.post(
    f"{KW_BASE_URL}/oauth/token",
    data={
        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "assertion":  assertion,
        "client_id":  CLIENT_ID,
    },
)
access_token = resp.json()["access_token"]
```

> JWT Assertion does not return a refresh token. Generate a new JWT and request a new access token as needed.

For a complete implementation guide, see [Authentication → JWT Assertion flow](authentication.html#jwt-assertion).

## Step 4 — Update All API Calls

Regardless of which flow you selected, all API requests must include `Authorization: Bearer` and the API version header:

cURL Python

api-call.sh Copy

```bash
curl -s \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "X-Accellion-Version: 28" \
  "https://your-instance.kiteworks.com/rest/folders/top"
```

api_call.py Copy

```python
session = requests.Session()
session.headers.update({
    "Authorization":       f"Bearer {access_token}",
    "X-Accellion-Version": "28",
})

response = session.get(f"{KW_BASE_URL}/rest/folders/top")
```

> Your existing client secret does not need to change. The same client secret used in the old flow works in the new flow.

## Frequently Asked Questions

The following questions address common concerns when upgrading authentication flows.

### What is the recommended authentication method for Kiteworks API integrations?

Kiteworks recommends OAuth 2.0-based authentication. Use **Authorization Code Flow** (shown as **Connect (Authorization Code)** in Admin UI) when a user logs in interactively via a browser. Use **JWT Assertion** for machine-to-machine automation without user interaction. JWT Assertion is only for use in secure, trusted server environments.

### Do I need to regenerate my client secret when upgrading authentication flows?

No. The client secret used in old flows continues to work in the new flows. You only need to regenerate it if it was previously exposed.

### Does JWT Assertion return a refresh token?

No. JWT Assertion does not return a refresh token. Generate a new signed JWT and request a new access token when the current token expires.

### Can I use JWT Assertion in a public-facing web application?

No. JWT Assertion allows impersonation of Kiteworks users and requires access to an RSA private key. It must only be used in secure, trusted server environments — never in client-side or publicly accessible applications.

### What happens to my existing API calls during the upgrade?

Your existing API calls continue to work until you update the client registration in Admin UI. After changing the registered flow, update your code to request tokens using the new flow before deploying.

## Next Steps

You've upgraded your authentication flow. Here's what to do next:

- [Upgrade to API v28 →](upgrade-api-v28.html) Add `X-Accellion-Version: 28` to all API requests and apply all v28 breaking changes.
- For complete implementation code, see [Authentication → Authorization Code Flow →](authentication.html#authorization-code) or [Authentication → JWT Assertion →](authentication.html#jwt-assertion).
- [API Reference →](api-reference.html) Explore all available endpoints.
