Skip to content

Acquire an outbound access token

Returns a cached OAuth client-credentials access token, refreshing it from the configured token endpoint when it is missing or near expiry.

Field Value
Operation ID OP-13
Trigger Consumer code calls IAccessTokenClient.GetToken() before calling a downstream API.
Inputs TokenUrl, ClientId, ClientSecret, GrantType, Scopes (all code-set properties), and the current HttpContext only on the refresh path.
Outputs An OAuth access token string, returned from cache or from a fresh refresh; there is no post-refresh validity check before returning or caching it**.
Primary components OktaTokenClient.GetToken()
Entry point src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/OktaTokenClient.cs

Steps

  1. If the cached token is missing or not IsValidAndNotExpiring (empty token, or expiring within 30 seconds), call GetNewAccessToken() (BR-AUTH-017)
  2. GetNewAccessToken: create a new HttpClient; set Authorization: Basic base64(ClientId:ClientSecret); POST a form body of grant_type, scope, and redirect_uri = {Request.Scheme}://{Request.Host} to TokenUrl (BR-AUTH-018)
  3. response.EnsureSuccessStatusCode(), which throws on a non-2xx response; deserialize with Newtonsoft and set ExpiresAt = UtcNow + ExpiresIn seconds.
  4. Return AccessToken.

Process flow

The following diagram visualizes this operation's control flow.

flowchart TD
    Start([GetToken called]) --> Valid{Cached token valid and not expiring?}
    Valid -->|Yes| Return([Return cached AccessToken])
    Valid -->|No| New[GetNewAccessToken]
    New --> Post["POST TokenUrl with Basic auth + form body"]
    Post --> Success{2xx response?}
    Success -->|Yes| Cache["Deserialize, cache token, set ExpiresAt"]
    Success -->|No| Throw([EnsureSuccessStatusCode throws])
    Cache --> Return

Failure and edge-case behavior

  • A non-2xx response from the token endpoint throws from EnsureSuccessStatusCode().
  • HttpContext is only read when building redirect_uri on the refresh path (step 2); a cache hit (step 1) returns without touching HttpContext at all. Calling this outside a request only throws NullReferenceException when a refresh is actually needed*.
  • After a successful refresh, the deserialized token value is cached and returned without any additional validity check — the response is trusted as-is once EnsureSuccessStatusCode() passes.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/OktaTokenClient.cs