UPDATE: "API Access Management" has been selected and implemented.

We need to include additional information in tokens used by BOFE for authentication (like maker/checker status and groups related to BOFE roles). Currently, BOFE calls iam-manger with the current token and iam-manager calls OKTA admin API to fetch these info which is a lot of calls (we hit OKTA’s rate limiting threshold) and this is also very time consuming. Unfortunately, with our current setup it’s not a straight forward thing to do.

  1. Enable "API Access Management" features in Okta (preferred variant)

    • (plus) We can customise tokens to include information needed by BOFE, increasing speed of requests made to backoffice-manager because backoffice-manager do not need to contact iam-manager to fetch this info

    • (plus) Would allow adding additional claims to any Okta token, not just BO tokens, this would be useful for SRE squad as they also needed to include additional information in tokens used by their services (logging into infrastructure services).

    • (plus) Can be delivered sooner than custom solution.

    • (minus) There’s a possibility that not everything we need can be implemented in using Okta Expression Language and we will need to implement it using Inline hooks.

    • (minus) Costs additional $2 USD/MAU on top of our Okta subscription.

    • Approx. work estimate: ~1 week (depends on SRE)

  2. Implement our own tokens with token exchange

    • (plus) We can customise tokens to include information needed by BOFE, increasing speed of requests made to backoffice-manager

    • (plus) We can check if session was revoked in Okta without adding latency to BOFE operations

    • (plus) Potential to improve disaster-recovery in case of Okta outage

    • (minus) We must manage our own keys

    • (minus) It will require BOFE to call additional endpoint on login and during token refresh

    • Approx. work estimate: ~2 weeks (IAM + BOFE)

1. Okta API Access Management (current solution)

Okta doesn’t support customising tokens in normal subscription. Their focus is more on being Identity Provider and tokens issued by them aren’t meant to function as tokens for protecting APIs. If we want to use Okta for that, they offer a feature called API Access Management, this allows us to create Custom Authorization Servers (“authorization” in the title is related to OAuth terminology, not authorization as a concept). They can be used to customise tokens returned by Okta to include all the information we need to do authentication and authorization in our backend services.

This would also solve a problem we currently have with not having enough control over lifetime of the tokens and we are forced to use validity period set by Okta (60minutes). Shorter lifetimes are better for security, because they can limit how useful token is to attacker when it leaks.

Tokens are customised using Inline hooks which allows us to change token content from iam-manager. This increases latency when fetching tokens, because Okta must contact our servers, but lifts the limitations of what’s possible directly in Okta. We would also need to expose additional endpoints to public internet, expanding our attack surface.

Besides these concerns activating this feature allows us to do what we need in a relatively short time and with minimal changes to BOFE and backoffice-manager.

Custom claims format

We include a backoffice claim into Okta issued access and id tokens. Currently they contain roles extracted from groups assigned to the user for which the token is being issued. Roles created by filtering groups with chosen prefix (currently bofe-{env}) and stripping the prefix. Also additional roles maker and checker are included based on user status as a maker/checker, determined by linked object relationship in Okta.

{
    "sub": "{Okta user ID}",
    "aud": "{client_id}",
    "profile": {
        ...
    },
    "backoffice": {
      "roles": [
          "maker",
          "checker",
          "accounts",
          "..."
      ]
    }
}

2. Custom tokens (not used)

Most Okta integrations use Okta only as identity provider to establish identity in their own authentication systems. That’s what Okta is built around. Implementing custom tokens aligns our solution with what Okta expects.

Idea is to change tokens currently used by BOFE for a new kind of token issued by iam-manager.

Because these tokens are independent of Okta, we have full control over their content and lifetime. This means we can include all the necessary information for back-office services. Especially on GET requests, where we can tolerate some amount of eventual consistency, this would improve latency of BOFE endpoints and help us side-step Okta rate-limits, which we are currently hitting.

We can also easily control their lifetime allowing us to do faster access revocation, limiting the security impact in case the token leaks.

Technical details

BOFE exchanges access_token from Okta for our custom token by sending request to /bank-user/token endpoint in iam-manager service with Authorization: Bearer {Okta access_token}, header.

iam-manager than checks if the supplied token is valid and issues our custom token containing all the necessary information. The new token validity is bound by the validity of supplied access_token.

When the custom token expires BOFE requests a new one in the same way.

Example token payload:

{
    "sub": "{Okta user ID}",
    "exp": {expiry less or equal epxiry of Okta token},
    "iat": {current timestamp},
    "aud": "{App client id}",
    "profile": {
        "first_name": "...",
        "middle_name": "...",
        "last_name": "...",
        "email": "...",
        ...
    },
    "roles": [
        "maker",
        "checker",
        "accounts",
        "..."
    ]
}