OAuth flows and tokens β
This page is the technical guide to implement OAuth in your application. It explains what happens under the hood when your app accesses clinic data through GipoNext APIs.
π‘ Prerequisites
Before reading this page, make sure you understand:
- The two-identity model (application + user), explained in the next section
- Register your application, to obtain
client_idandclient_secret
π‘ Implementation note
Use battle-tested OAuth 2.0 libraries for your language/framework (for example IdentityModel for .NET, passport-oauth2 for Node.js, requests-oauthlib for Python). Building OAuth from scratch can introduce serious security risks.
Developer credentials and system access credentials β
OAuth 2.0 is the standard that allows your application to access APIs on behalf of a user, without handling the user's password directly. The user signs in on account.gipo.it, authorizes your app, and the system issues an access token used for API calls.
When implementing OAuth it is easy to think that user login is enough. In reality, two actors are always involved, and understanding this distinction is essential to integrate GipoNext APIs correctly.
π‘ In short
Every OAuth authentication requires two separate identities:
- The application β the software making the request (identified by a unique
client_id) - The user β the person performing interactive login
Both must be present and valid. One alone is not enough.
Summary table: application vs user β
| Application | User | |
|---|---|---|
| What it identifies | The software calling the APIs | The person using the software |
| How it is created | Registration on account.gipo.it from the Developer panel | Registration on giponext.it or activation by the clinic |
| Who approves it | Gipo administrator | Automatic (or clinic activation) |
| Credentials | client_id + client_secret | Username + password |
| When it is used | At every token request (background) | Only during interactive login |
| What it determines | Which scopes are configured for the app | Which tenant/clinic can be accessed |
| Can it be revoked | Yes, by a Gipo administrator | Yes, by user or clinic administrator |
| Recommended email | Team/shared mailbox | Personal mailbox |
Details on registration are available in Register your application.
The OAuth flow step by step β
This flow assumes your application is already registered and you already have client_id and client_secret. The application type selected during registration determines which flow to use:
| Application type | Recommended flow |
|---|---|
| Web server (PHP, .NET, Java, Python, and so on) | Authorization Code |
| Desktop or mobile app | Authorization Code (with PKCE if native) |
| Device without browser (printer, CLI, TV, and so on) | Device Code |
1. Get an access token from the authorization server β
Before your application can access data, it must obtain an access token from GipoNext's authorization server (account.gipo.it).
The access token grants access to resources controlled by requested scopes. Each scope enables a specific endpoint group (patients, agendas, reports, invoices, and so on).
During this step:
- Your app starts the OAuth flow with
client_id,scope, and other required parameters. - The user is redirected to
account.gipo.it, signs in, and sees the consent screen with requested permissions. - If the user accepts, the server issues an authorization code (or directly a token in Device Code flow).
- Your app exchanges the code at the token endpoint to obtain the access token.
β οΈ User consent is explicit
The user clearly sees your application name and requested scopes. You cannot get an access token unless the user explicitly grants access.
2. Validate granted scopes β
After receiving the access token, compare granted scopes in the response with the scopes your app needs. If the user grants only a subset (for example giponext.patients but not giponext.invoices), invoicing features will not be available.
Handle this gracefully: disable unsupported features or guide the user to grant missing permissions.
π‘ Best practice: incremental scopes
Request scopes when they are needed, not all at once. For example, request giponext.invoices only when the user enters your invoicing area.
3. Send the access token to APIs β
Include the access token in each HTTP call to GipoNext APIs through the Authorization header:
GET https://api.giponext.it/v2/tenants/{tenantId}/patients
Authorization: Bearer <access_token>
Accept: application/jsonβ οΈ Never pass token in URL
Do not send tokens as query parameters (?access_token=...): URLs may leak through logs, proxies, and browser history.
An access token is valid only for granted scopes. A token with scope giponext.patients cannot call invoicing or report endpoints.
4. Refresh the access token when it expires β
Access tokens have a limited lifetime (typically from hours to a few days, depending on configuration). When expired, API calls return 401 Unauthorized.
If you requested offline_access, you also received a refresh token. Use it to get a new access token without asking the user to sign in again:
POST https://account.gipo.it/connect/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=<refresh_token>
&client_id=<client_id>
&client_secret=<client_secret>If the refresh token is expired or revoked, the user must authenticate again. See Refresh token expiration below.
Scenarios by application type β
Web server applications β
For applications with a backend (PHP, .NET, Java, Python, Node.js, Ruby, and so on) that can open a browser and handle redirects.
The flow starts when your backend redirects the user's browser to account.gipo.it/connect/authorize with required parameters. After login and consent, the server redirects to your redirect_uri with a code. Your backend exchanges that code at the token endpoint and gets access_token and refresh_token.
Key /connect/authorize parameters:
| Parameter | Value |
|---|---|
response_type | code |
client_id | Your client_id |
redirect_uri | Your application URL (must match the registered URI) |
scope | Space-separated scopes (for example openid offline_access giponext.patients) |
state | Random value for CSRF protection (verify it returns unchanged) |
Store refresh_token securely and use access_token for API calls. When access token expires, use refresh token to obtain a new one without new login.
Installed applications (desktop or mobile) β
For native apps on Windows, macOS, Linux, Android, or iOS that can open a system browser.
The flow is similar to Authorization Code, with one key difference: native apps cannot keep a client_secret truly secret (code runs on user devices). In that case, use PKCE (Proof Key for Code Exchange) instead of client secret, or confirm with Gipo which configuration is supported for your app type.
Devices with limited input (Device Code) β
For devices without browser, CLI tools, batch integrations, or server environments where interactive login windows are not possible.
The user authorizes from a second device (PC or smartphone), while the main device polls waiting for token issuance.
Polling errors to handle:
| Error | Meaning |
|---|---|
authorization_pending | User has not authorized yet - retry after interval seconds |
slow_down | Polling is too frequent - increase waiting interval |
expired_token | device_code expired - restart from step 1 |
access_denied | User denied consent - stop polling and inform the user |
Refresh token is also renewed
Refresh token validity is sliding: if used regularly to request new access tokens, it keeps renewing without manual intervention.
If it remains unused until expiration, a new interactive authentication is required.
Background services (Windows Service, Unix daemon, and similar) β
For background applications that can log operational output, you can use Device Code: at startup, the service starts the flow and writes the code in a place visible to an operator, who completes authentication from another device.
As an alternative, create a small companion app dedicated to interactive authentication. That app stores access_token and refresh_token in secure storage shared with the background service, which can then call APIs without repeated user intervention.
Automatic periodic renewal
For applications with schedulers or periodic jobs, configure periodic token renewal. Renew often enough to refresh tokens before natural expiration and keep automated processes running.
Token size and lifetime β
| Token | Typical lifetime | Notes |
|---|---|---|
| Access token | Hours / days | Include in each API call. When expired, APIs return 401. |
| Refresh token | Weeks / months | Used to renew access token. Store securely. |
| Authorization code | Few minutes | Single use. Exchange immediately at token endpoint. |
β οΈ Store tokens securely
- Never store access or refresh tokens in browser
localStorage(JavaScript accessible). - Use secure storage such as
HttpOnly+Securecookies, Keychain (iOS/macOS), Credential Manager (Windows), or environment variables / vault for backend services.
Refresh token expiration β
Always design your code assuming refresh tokens may stop working. A refresh token can become invalid for the following reasons:
- User revoked access to your app from their account.gipo.it profile
- Token inactivity for too long (inactivity rotation)
- User account disabled or role changed by clinic administrator
- Active token limit reached for the same client + user combination
- OAuth client revoked by a Gipo administrator
When refresh token is expired or revoked, the token endpoint returns:
{
"error": "invalid_grant",
"error_description": "refresh token is expired"
}In this case, token renewal is not possible: user must authenticate again (Authorization Code or Device Code flow). Handle this path explicitly in your code by redirecting to the authorization flow.
Scopes: what each token controls β
Each access token is valid only for scopes granted by the user. Requesting a scope does not mean automatic access: the user decides what to authorize.
| Scope | What it enables |
|---|---|
openid | Base OpenID Connect flow (required) |
offline_access | Refresh token issuance |
giponext.patients | Patients (demographics, read/write) |
giponext.agenda | Agendas and appointments |
giponext.treatments | Treatments and products |
giponext.episodes | Clinical episodes |
giponext.medicalreports | Medical reports |
giponext.invoices | Invoicing |
giponext.fhir | FHIR endpoints |
See the full list in Scopes and authentication.
Reference endpoints β
| Endpoint | URL |
|---|---|
| Discovery (OpenID configuration) | https://account.gipo.it/.well-known/openid-configuration |
| Authorization | https://account.gipo.it/connect/authorize |
| Token | https://account.gipo.it/connect/token |
| UserInfo | https://api.giponext.it/v2/userinfo |
| Issuer | https://account.gipo.it |
Use the discovery document to resolve endpoints dynamically. It stays up to date and protects your integration from future URL changes.
Next steps β
- Register your application β how to register your application
- Scopes and authentication β full scope list and resource mapping