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: alwaysBearerfor use withAuthorization: Bearer <access_token>.access_token: often a JWT (three dot-separated segments; value starts witheyJ…when base64-decoded header is JSON).refresh_token: opaque string; often a GUID form like04176de6-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=/§ok=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.