OAuth Integration - Huddle/huddle-apis GitHub Wiki

Introduction

Huddle uses OAuth 2.0 (RFC 6749) for authorisation when calling Huddle APIs. The authorisation server is implemented by the Identity service (Huddle.Login.Api in the Identity repository): it exposes the interactive login and consent UI, the token endpoint, and related routes.

The OAuth 2.0 framework is summarised at oauth.net. This page describes how Huddle’s login host behaves. Unless stated otherwise, behaviour matches the standard.

OAuth 2.0 and Bearer are not alternatives

OAuth 2.0 Bearer
What it is The authorization framework: how your app gets an access token (authorize → /token, refresh, grants, etc.). The HTTP scheme for sending that access token on API requests. Defined in RFC 6750 (“OAuth 2.0 Bearer Token Usage”).
Typical use Call the login host (/request, /token, …) using OAuth 2.0 flows. Call Huddle APIs with Authorization: Bearer <access_token>.

The access token you obtain through OAuth 2.0 is the same string you present as a Bearer token. Older examples sometimes used a non-standard Authorization: OAuth2 … header; Bearer is the standard form and what this documentation uses.

Base URL: the login server hostname is environment-specific (for example https://login.huddle.net in production). Local development commonly uses https://login.huddle.local. All paths below are relative to that base URL.

Implementation reference (Identity)

These routes are registered on the login API (see ServiceConfiguration in Huddle.Login.Api):

Path Role
GET /request Authorisation endpoint (start authorisation code flow). Query: response_type, client_id, redirect_uri, optional state, optional idp.
GET /request/{requestId} Continue or error paths for an access request.
POST /token Token endpoint: authorization_code, refresh_token, client_credentials, password, and other supported grant types (see Password grant).
POST /refresh Same token issuance pipeline as /token (registered alias).
POST /grant/{clientAuthorizationRequestGuid} User approves an access grant (after login/consent).
POST /deny/{clientAuthorizationRequestGuid} User denies an access grant.
POST /impersonation Impersonation token (requires signed requests where documented).
GET /.well-known/openid-configuration Metadata for JWT/OIDC-style configuration.
GET /.well-known/jwks.json Public keys (JWKS) for validating tokens where applicable.
GET /saml/browser-sso SAML SSO entry (enterprise single sign-on).

Interactive login and my.huddle-specific flows also use /login, /login/entry, etc., as described later in this page.

Feature support

Topic Behaviour
Client profiles Web server and user-agent style public clients are supported; exact registration depends on your app.
Access grant (authorisation code) lifetime Configurable per client; often long-lived (for example up to one year).
Access token lifetime Configurable (TokenExpirySeconds / deployment-specific identity settings). Typical values are on the order of minutes (for example 20 minutes in many configurations)—always rely on the expires_in value returned with the token.
Refresh tokens Issued for appropriate grants so clients can obtain new access tokens without re-prompting the user.
DPoP The token endpoint accepts an optional DPoP proof for clients where DPoP is enabled (see token request handling in TokenIssueHandler).

Registering your client

Taken from OAuth 2.0 Framework:

client

An application making protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices).

Before calling Huddle APIs you register an OAuth client with Huddle.

Please supply the following to [email protected]:

  • Application name
  • Company (if appropriate)
  • Contact name, phone and address
  • Contact email
  • Redirect URI (see OAuth spec. “redirect_uri”; must match later requests exactly)
  • Whether this is a web app, desktop app, or device app
  • Short description of your application

You should receive acknowledgement within one business day; processing is typically within three business days.

After registration is approved, Huddle provisions your OAuth client and provides your client_id. If your application is registered as a confidential client (can store a secret securely), you will also receive a client_secret.

Obtaining end-user authorization

When a user first uses your application, send them to the authorisation server so they can sign in and approve access. After approval, the user is redirected to your redirect URI with an authorization code.

Reference: OAuth 2.0, Sections 3 and 3.1.

Initial request

Issue a GET to the authorize endpoint:

GET /request?response_type=code&client_id=s6BhdRkqt&redirect_uri=MyAppUri%3A%2F%2FMyAppServer.com%2FreceiveAuthCode&state=xyz HTTP/1.1
Host: login.huddle.net
Key Value
response_type Must be code. Other values are not supported.
client_id Your registered client id.
redirect_uri Your registered redirect URI (URL-encoded).
state Recommended: opaque value to prevent CSRF; returned on redirect.
idp Optional: identity provider hint where applicable.

For web apps the redirect often uses https://. Custom URL schemes are supported for native apps.

Typical response

The response is usually 200 HTML: login and consent. After the user signs in and approves, the browser is sent to the consent step; approving issues a redirect to your redirect_uri with code=… (and state if you sent one).

Legacy documentation sometimes showed a form posting to /authoriseGrantRequest. The Identity UI posts approval to POST /grant/{accessGrantId} (the exact grant id is in the rendered page). Denial uses POST /deny/{accessGrantId}.

Successful redirect

HTTP/1.1 302 Found
Location: MyAppUri://MyAppServer.com/receiveAuthCode?code=ilWsRn1uB1&state=xyz

The user agent then loads your redirect URI:

GET /receiveAuthCode?code=ilWsRn1uB1&state=xyz HTTP/1.1
Host: MyAppServer.com

Persist the code (one-time use) and validate state if you used it.

Handling errors

If the user denies access or an error occurs, you receive query parameters such as error and error_uri instead of code.

Example

GET /receiveAuthCode?error=access_denied&error_uri=https%3A%2F%2Flogin.huddle.net%2Fdocs%2Ferror%23AuthRequestAccessDenied HTTP/1.1
Host: MyAppServer.com
Error code Meaning
invalid_request Missing or invalid parameters.
unauthorized_client Client is not allowed to use Huddle (e.g. disabled app—see error_description).
access_denied User or server denied the request.
unsupported_response_type response_type not supported.
invalid_client Unknown client_id.
redirect_uri_mismatch redirect_uri does not match registration.

invalid_scope is not used by Huddle for external clients as described previously.

Obtaining access and refresh tokens

Exchange the authorization code for tokens by POSTing to /token with Content-Type: application/x-www-form-urlencoded.

Reference: OAuth 2.0, Sections 4, 4.1, 4.1.1, 4.2, 4.3, 4.3.1.

Initial request

Requests to this endpoint can be secured (client secret or signing) where your client is configured for it.

POST /token HTTP/1.1
Host: login.huddle.net
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&client_id=s6BhdRkqt&redirect_uri=MyAppUri%3A%2F%2FMyAppServer.com%2FreceiveAuthCode&code=i1WsRn1uB1
Key Value
grant_type authorization_code
client_id Your registered client id
redirect_uri Same redirect URI as in the authorize request
code The authorization code from the redirect

The body parameter name must be code (not authorization_code).

Token response (authorization code)

A successful POST /token response uses application/json and matches the OAuth 2.0 token response (RFC 6749 §5.1). In production you will typically see:

  • token_type: always Bearer for use with Authorization: Bearer <access_token>.
  • access_token: often a JWT (three dot-separated segments; value starts with eyJ… when base64-decoded header is JSON).
  • refresh_token: opaque string; often a GUID form like 04176de6-0c9b-4a3d-8cd4-c9ac71110d8a.
  • expires_in: access token lifetime in seconds (for example 1200 = 20 minutes).
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.sig",
    "token_type": "Bearer",
    "expires_in": 1200,
    "refresh_token": "04176de6-0c9b-4a3d-8cd4-c9ac71110d8a"
}

The access_token value above is truncated for readability; real JWTs are longer. Use expires_in to schedule refresh; send the access token on API calls as documented in Calling the Huddle APIs.

Handling errors

Invalid or unauthorized token requests return 400 (or 403 in some client-disabled cases) with JSON error details.

Example

HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store

{
   "error":"invalid_grant",
   "error_description":"The authorisation grant was revoked",
   "error_uri":"https://login.huddle.net/docs/error#TokenRequestInvalidGrant"
}
Error code Meaning
invalid_request Malformed request.
invalid_client Invalid client_id or credentials.
unauthorized_client Client cannot use this grant (e.g. disabled).
invalid_grant Code wrong, expired, or redirect mismatch.
unsupported_grant_type Grant type not supported.
invalid_scope Documented in RFC; Huddle usage is limited for external access.

Use the parameter name code (not authorization_code) in the POST /token form body, as in the example under Initial request in this section. Parse the JSON response: read access_token, token_type, refresh_token, and expires_in, and handle OAuth error JSON on failure.

Client credentials flow

Confidential clients can obtain an access token with client credentials (no end-user consent). There is typically no refresh token; request a new access token when expired. Access level is agreed out-of-band.

Request

POST /token HTTP/1.1
Host: login.huddle.net
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=YQZisfkc7sVPAcX&client_secret=4FAE59C35C6B8
Key Value
grant_type client_credentials
client_id Your client id
client_secret Your client secret

Client credentials response

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 86400
}

There is usually no refresh_token in this flow; request a new access token when expires_in elapses.

Resource owner password grant (password)

Some confidential clients (for example internal tools and automation) may exchange a user’s username and password for tokens by posting to POST /token with grant_type=password. This is the OAuth 2.0 resource owner password credentials grant (RFC 6749 §4.3).

Security: Only use this from trusted server-side code. Do not put client_secret or the user’s password in browser apps, mobile apps, or public repositories. Huddle may restrict which client_id values are allowed to use this grant.

Request

POST /token HTTP/1.1
Host: login.huddle.test
Content-Type: application/x-www-form-urlencoded

grant_type=password&client_id=your-client-id&client_secret=your-client-secret&username=user.name&password=your-password
Key Value
grant_type password
client_id Registered client id
client_secret Client secret (when the client is confidential)
username User’s username (format as agreed for your environment, e.g. email or short name)
password User’s password

The Host must match your environment’s login server (for example login.huddle.test, login.huddle.local, or login.huddle.net).

Response

On success, the JSON matches other grants: access_token (JWT), token_type: "Bearer", expires_in (seconds), and typically refresh_token (opaque string, often GUID-shaped)—same shape as Token response (authorization code).

{
    "access_token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIs...",
    "expires_in": 1200,
    "refresh_token": "04176de6-0c9b-4a3d-8cd4-c9ac71110d8a",
    "token_type": "Bearer"
}

Use the access token on API calls as Authorization: Bearer <access_token>. Refresh using grant_type=refresh_token when supported for your client.

Calling the Huddle APIs

Include the access token on every API request. Prefer the Authorization header with the Bearer scheme (RFC 6750).

Reference: OAuth 2.0, Sections 5, 5.1, 5.1.1, 5.2, 5.2.1.

Including your token

GET https://api.huddle.net/v2/calendar/workspaces/all HTTP/1.1
Authorization: Bearer vF9dft4qmT
Accept: application/xml
Host: api.huddle.net

Alternatively, some endpoints accept the token as a query parameter (legacy):

GET https://api.huddle.net/v2/calendar/workspaces/all?oauth_token=vF9dft4qmT HTTP/1.1
Accept: application/xml
Host: api.huddle.net

Handling errors

Invalid or expired tokens may yield 400, 401, or 403 with a WWW-Authenticate header, for example:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm='huddle', error_uri="https://login.huddle.net/docs/client-error#TokenExpired", error="invalid_token"
Error code Meaning Typical status
invalid_request Malformed request / token presentation 400
invalid_token Expired or invalid token 401

insufficient_scope is defined in the OAuth 2.0 spec but is not returned by Huddle’s APIs.

Refreshing your access token

Use the refresh token with grant_type=refresh_token before expires_in elapses. If you call an API with an expired access token, you may receive invalid_token (see above).

Reference: OAuth 2.0, Sections 4.1.4, 4.2, 4.3, 4.3.1.

Request

POST /token HTTP/1.1
Host: login.huddle.net
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&client_id=s6BhdRkqt&refresh_token=n4E9O119d

Add client_secret (or signing) when your client is configured for secured requests.

Success and error JSON shapes match the token response (authorization code) section.

Impersonation

For supported admin scenarios, POST /impersonation can exchange a refresh token for a short-lived access token for another user. Requests must follow signing requirements where enforced.

POST /impersonation HTTP/1.1
Host: login.huddle.net
Content-Type: application/x-www-form-urlencoded
Accept: application/json

client_id=s6BhdRkqt&key_uri=a_key&refresh_token=a_refresh_token&user=https://api.huddle.net/users/100&target_user=https://api.huddle.net/users/200&cipher=cipher&sig=a_signature
Key Value
client_id Registered client id
key_uri HTTPS URI of your public key (.pem)
refresh_token Refresh token for the impersonating user
user Impersonator user URI
target_user Target user URI
cipher Signing algorithm (e.g. ES512)
sig Signature over the parameters

Typical response

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 300
}

No refresh token is returned for this one-time impersonation access token.

Login initiation for my.huddle only

First step for the my.huddle client to start login.

Access request (GET)

GET /login HTTP/1.1
Host: login.huddle.net

Typical response

HTML form; sectok is issued as a cookie/hidden field.

HTTP/1.1 200 OK
Set-Cookie: sectok="44cfe678-7902-fdfe-6548-ad2d4a30f938"; Domain=login.huddle.net; Path=/; Secure; HttpOnly
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache, no-store

Create access request (POST)

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cookie: sectok=44cfe678-7902-fdfe-6548-ad2d4a30f938

client_state=/&sectok=44cfe678-7902-fdfe-6548-ad2d4a30f938

Redirect to login entry

HTTP/1.1 302 Found
Location: /login/entry?access_request=88f611e2-7902-4c24-915e-ad2d4a30f938
Cache-Control: no-cache, no-store

OAuth 2.0 and SSO

Username or email

GET /login/entry/?access_request=requestid HTTP/1.1
Host: login.huddle.net

Typical response

HTML form posting back to /login/entry with access_request and user_identifier.

POST

POST /login/entry HTTP/1.1
Content-Type: application/x-www-form-urlencoded

access_request=88f611e2-7902-4c24-915e-ad2d4a30f938&[email protected]

Continue to SAML SSO

HTTP/1.1 204 No Content
Cache-Control: no-cache, no-store
Location: /saml/browser-sso?idp=huddle&access_request=88f611e2-7902-4c24-915e-ad2d4a30f938

Securing requests

Some token and impersonation calls can require a client secret or request signing so Huddle can verify the caller.

Client secret

If your client has a secret, include client_secret in the form body for endpoints that support it (for example refresh or client credentials), as documented for that endpoint.

Example:

/token?grant_type=refresh_token&client_id=your-client-id&client_secret=your-client-secret&refresh_token=a-refresh-token

Request signing

For supported clients, supply key_uri (public key PEM), cipher (e.g. ES512), and sig (signature). Register a Client Key URI template so key_uri is under your allowed pattern.

Example:

/token?grant_type=authorization_code&client_id=example-client&key_uri=https://example.com/public-key.pem&cipher=es512&sig=the-hash-of-the-request

sig must be the last parameter.