A3BC — Build digital trust. Together.
Français English
Documentation/OIDC integration/Tokens and lifetimes

Tokens and lifetimes

Code, id_token, access_token, client_credentials token and webhook signing key: what each is for, how long it lives, how to protect it.

Several “tokens” are involved in an integration. They do not look alike and do not serve the same purpose: mixing them up is the first source of mistakes.

Overview

Authorization code id_token access_token (user flow) client_credentials token Webhook signing key
Who authenticates to whom A3BC to your site (through the user) A3BC proves identity to your server Your server to A3BC, on behalf of the user Your server to A3BC, no user A3BC to your server
Where to get it code parameter of the callback Token endpoint response Token endpoint response Token endpoint, grant_type=client_credentials Delivered by A3BC when the webhook is configured
Form Opaque string Signed JWT (3 parts) Opaque string Opaque string 32-byte key in base64 (44 characters)
What it is for Being exchanged for the tokens Reading the claims, after verification Calling userinfo and the document API Calling the delayed sharing API Checking that the webhook really comes from A3BC
Lifetime Very short, single use Given by exp (10 minutes in the guide’s example) Given by expires_in; access to information is guaranteed for 30 minutes About 10 minutes (expires_in: 599 in the guide) Until rotation (versioned key: v1, v2…)
Where to keep it Nowhere: exchange it immediately Keep only the useful claims, not the token In memory, for the duration of the calls In memory; request a new one each time Secrets manager, server-side

The authorization code

It arrives in the callback URL (?code=…&state=…). It is only worth something for a few moments: your server exchanges it right away at the token endpoint, with its credentials. It is single-use: a second attempt is refused. It goes through the browser, which is why it gives nothing without your client_secret.

The id_token: the proof of identity

It is a JWT: three base64url-encoded blocks separated by dots (header, payload, signature). The payload contains:

  • the claims the user shared (given_name, birthdate…);
  • information about the token itself: iss (who issued it), aud (for whom: your client_id), sub (the user), iat/exp (issued at / expires at), nonce (yours), and technical claims (at_hash, auth_time, jti, sid, rat).

Never read the content without verifying the signature: anyone can forge a JWT that looks valid. Verification uses the public keys of the jwks_uri; see Verify the tokens. Once verified, extract and store the claims you need: the token itself expires quickly.

The access_token: the key to call the user’s APIs

It represents the consent given by this user for this transaction. You present it in the Authorization: Bearer <access_token> header to:

  • the userinfo endpoint (which returns the same claims as the id_token);
  • the URL of a document claim (private:doc.*).

In the guide’s examples it is not a JWT: treat it as an opaque string, do not try to decode it. Its validity is given by expires_in in the token endpoint response. In all cases, information can only be retrieved for 30 minutes after consent: call the APIs right away.

Security rules: never in a URL (it would be logged), never in a browser or mobile app, never in logs, never sent anywhere other than A3BC endpoints.

If the refresh_token grant was enabled for your RP (optional and reserved for delayed sharing), you also receive a refresh_token. Only use it if A3BC told you to.

The client_credentials token: access without a user

For delayed sharing, the user is no longer there when you query the API (that is the point). Your server therefore authenticates itself, with its credentials:

curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials -d scope=private:delayed_sharing \
  https://oidc-sandbox.a3bc.io/oauth2/token

It is only valid for the private:delayed_sharing scope and lives about 10 minutes: request a new one for each call, or cache it until expires_in minus a margin.

The webhook signing key: authentication the other way round

For all the other keys, you prove your identity to A3BC. Here, A3BC proves its identity to your server: each notification carries a signature computed with a key that only you and A3BC share. It is not an access token and is never sent anywhere. See Webhooks.

The RP credentials

Credential Role Confidential?
client_id Identifies your service (also in the id_token aud). No
client_secret Authenticates you at the token endpoint (client_secret_basic). Yes

client_secret_basic means you send Authorization: Basic base64(client_id:client_secret). HTTP libraries do it with an auth=(client_id, client_secret) parameter (Python requests) or -u client_id:client_secret (curl).