Using OIDC to access REST APIs

Gabriel Zachmann, Marcus Hardt

Jan 2023

Outline

  • Problem Description
  • Tools for obtaining access tokens
    • oidc-agent
    • mytoken
  • Authentication based on access tokens
    • flaat

Problem Statement

  • OIDC (OpenID Connect) is most often used with web-browser
    • Tokens end up at webserver
    • Webserver can access APIs
  • Direct access (without involvement of web-browser) not well supported
  • Copy-paste scenarios are not feasible: Tokens expire after ~1h.
  • Our goal: Support Non-web + rare-user interaction authentication
  • Particular use cases:
    1. Authenticated access to remote services
      • from Desktop / Commandline
      • access to storage (webDAV), or remote hosts (SSH)
    2. Long running compute jobs

oidc-agent

oidc-agent
https://indigo-dc.gitbook.io/oidc-agent/

  • Goals:
    • Provide Access Tokens to user
    • Minimal user interaction
  • Analogy to ssh-agent is intentional:
    • Runs on local workstation of the user
    • Stores “private keys” on local workstation of the user
    • oidc-gen: Generate an OIDC configuration
    • oidc-add: Load an OIDC configuration
    • oidc-token: Obtain OIDC Access Tokens

Security

  • oidc-agent uses Refresh Tokens
    • Require high level of protection
  • Encrypted storage on disk
  • Obfuscated storage in RAM

Using oidc-agent

  • Once in a life time (~1 Year): Create a configuration: (triggers an auth-code-flow; device-code-flow is also supported)

    oidc-gen eduteams --issuer https://proxy.eduteams.org  --scope max

  • Once per reboot: Load encrypted configuration into memory (triggers password prompt; GUI or cmdline; May be skipped)

    oidc-add eduteams

  • Often: Obtain token:
    (Auto-adds config, when oidc-add was skipped)

    oidc-token eduteams
    oidc-token https://proxy.eduteams.org

Use case 1

  • “Authenticated access to remote services”

    URL=https://proxy.eduteams.org; \
        curl $URL/OIDC/userinfo -H "Authorization: Bearer `oidc-token $URL`" | jq          

Solved

Bottomline oidc-agent

  • Use case #1 solved: “Authenticated access to API”:
  • Supported Platforms:

mytoken

mytoken
https://mytoken-docs.data.kit.edu

  • Goals:
    • Provide Access Tokens to long-running jobs
    • No interaction with the user
    • DO NOT release Refresh Tokens to the infrastructure
  • Challenge:
    • Balance Security vs. Convenience
  • Approach:
    • Introduce mytoken server: Obtains Refresh Token via authorisation code flow.
    • Introduce new token type, called “mytoken
    • Refresh Tokens (stay on server) are encrypted with mytoken (given to client)

Balance Security vs. Convenience

  • mytokens are jwt style tokens, that
    • contain Capabilities: “What can I do with the mytoken”
    • contain Restrictions: “What are the limits to use the mytoken”
    • support inheritance: “Use mytoken to derive another more limited mytoken”
  • See it life and in colour:



Demo

  • The following examples are also shown in the live demo
  • Obtain a mytoken:
    1. Via commandline:
    mytoken MT --oidc --issuer https://proxy.eduteams.org
    1. Via web: from the mytoken server
  • We store the mytoken obtained in $MYTOKEN

Examples

  • Inspect the mytoken:

    $ echo $MYTOKEN | decodejwt.sh
    {
        "alg": "ES512",
        "typ": "MT+JWT"
    }
    {
    "ver": "0.6",
    "token_type": "mytoken",
    "iss": "https://mytoken.data.kit.edu/",
    "sub": "N071dtAYzya4W32aHGXaze07ywqKMZ/2B2MSVY4uBuw=",
    "seq_no": 1,
    "aud": "https://mytoken.data.kit.edu/",
    "oidc_sub": "7ca006d6b7e61023cec493a74e57849ae9145815@eduteams.org",
    "oidc_iss": "https://proxy.eduteams.org",
    "exp": 1674835490,
    "nbf": 1674144337,
    "iat": 1674144337,
    "auth_time": 1674144337,
    "jti": "0502ae85-1dde-44a0-8965-5db2360fe4ed",
        [...]
    }

Examples

  • Inspect the mytoken (continued)

    [...]
    "capabilities": [
        "AT",
        "tokeninfo"
    ],
    "restrictions": [
        {
            "exp": 1674230630
        },
        {
            "nbf": 1674749030,
            "exp": 1674835490
        }
    ]

Examples

  • Get another mytoken, using a $MYTOKEN:

    $ mytoken MT --restrictions '{
        "nbf": 1674760000,
        "exp": 1674800000,
        "usages_AT": 1,
        "geoip_allow": [
            "DE"
        ]
    }' --MT $MYTOKEN | decodejwt.sh 
    [...]
        "capabilities": [
            "AT",
            "tokeninfo"
        ],
        "restrictions": [
            {
                "exp": 1673969694,                                                                         
                "exp": 1674600000,
                "usages_AT": 1,
                "usages_other": 1
            }
        ]
    }

Examples

  • Get an Access Token from a mytoken:
    Find decodejwt.sh here.

    $ mytoken AT --MT $MYTOKEN | decodejwt.sh
    {
        "alg": "RS256",
        "typ": "JWT",
        "kid": "PUYOirA3Y-d_dGpdj4iJDHw4zHa8IY-bhZdaEj0rjbU"
    }
    {
        "exp": 1673967087,
        "iat": 1673963487,
        "auth_time": 1673958960,
        "jti": "8ff30cdd-cbab-4ee8-bf9d-5e219fd55324",
        "iss": "https://aai.egi.eu/auth/realms/egi",
        "sub": "d7a53cbe3e966c53ac64fde7355956560282158ecac8f3d2c770b474862f4756@egi.eu",
        "typ": "Bearer",
        "azp": "mytoken",
        "session_state": "9336c983-befa-476c-b494-82a49f04d661",
        "scope": "openid eduperson_unique_id eduperson_scoped_affiliation eduperson_entitlement cert_entitlement ssh_public_key profile email orcid",
        "sid": "9336c983-befa-476c-b494-82a49f04d661",
        "authenticating_authority": "https://idp.scc.kit.edu/idp/shibboleth"
    }

Bottomline mytoken

  • mytokens can be adjusted to the situation in which they are used
  • mytokens can be as safe as possible – and as unsafe as necessary
  • mytokens can be revoked
  • mytokens can mostly be used just as any other OIDC JWT token
  • mytoken server https://mytoken.data.kit.edu will soon be hosted according to the EugridPMA Credential Store.
  • Supported Platforms:

Serverside

flaat
https://flaat.readthedocs.io

  • Goals:
    • Python
    • Simple to use
    • Flexible to use
    • Just add “AAI” to python REST API

flaat

  • Usage
    • Define requirement(s) (on user)
    • Use python decorator mechanism to enable access control
  • Entitlements: flaat natively supports
  • Can be used to support other profiles
    • e.g. WLCG or SciTokens
  • Supported Platform:
    • python3.6+

Example

Require an authenticated user

# Endpoint which requires of an authenticated user
@app.get("/authenticated")
@flaat.is_authenticated()
def authenticated(request: Request,
    return "This worked: there was a valid login".

Example

Require an authenticated user to carry two entitlements

# The user needs belong to a certain virtual organisation
vo_requirement = get_vo_requirement(
    [
        "urn:geant:eduteams.org:service:eduteams:group:LAGO-AAI",
        "urn:geant:eduteams.org:service:eduteams:group:eduTEAMS",
    ],
    "eduperson_entitlement",
    match=2,
)

@app.get("/authorized_vo")
@flaat.requires(vo_requirement)
def authorized_vo(request: Request):
    return "This worked: user has the required entitlement(s)"

Bottomline flaat

  • Simple support for enforcing AAI in python REST interfaces is available

Summary

Summary

  • Using OIDC in REST APIs is
    • straightforward
    • on client and server
  • The presented tools are a subset of available tools
  • All tools are developed at Karlsruhe Institute of Technology (KIT)
  • For questions:
    • Contact: hardt@kit.edu