# Client Credentials and Discouraged Grants — Authentication & Authorization

Source: https://www.skillbyai.com/en/authentication/o-grants

> Service-to-service access, and why implicit and password grants are going away.

## Machines and legacy flows

The **client credentials grant** serves **service-to-service** calls with no user involved: the service authenticates as itself (client secret, or preferably a private-key JWT or mutual TLS) and receives an access token with limited scopes. The **implicit grant** returned tokens directly in the redirect URL fragment, exposing them to browser history, referrers and injection; it is superseded by the authorization code flow with PKCE. The **resource owner password credentials grant** makes the app collect the user's password, which defeats the point of OAuth, trains users to type passwords into third-party apps and cannot support MFA or passkeys well. RFC 9700 says not to use either, and the OAuth 2.1 draft omits them. Check the current draft status before citing OAuth 2.1 as final.

## Client credentials from Python

Using requests; cache the token until shortly before it expires.

```python
import time
import requests

_cache = {'token': None, 'exp': 0}

def service_token() -> str:
    if _cache['token'] and time.time() < _cache['exp'] - 60:
        return _cache['token']
    resp = requests.post(
        'https://auth.example.com/token',
        data={'grant_type': 'client_credentials', 'scope': 'inventory:read'},
        auth=(CLIENT_ID, CLIENT_SECRET),   # HTTP Basic client authentication
        timeout=5,
    )
    resp.raise_for_status()
    body = resp.json()
    _cache.update(token=body['access_token'], exp=time.time() + body['expires_in'])
    return _cache['token']

items = requests.get('https://inventory.internal/items',
                     headers={'Authorization': f'Bearer {service_token()}'}, timeout=5)
```

## Scope machine clients tightly

Give each service its own client ID with the smallest set of scopes, so a leaked secret affects one integration and shows up clearly in audit logs.

**Quiz:** Which grant fits a nightly batch job calling an internal API with no user present?

- [x] Client credentials
- [ ] Implicit
- [ ] Resource owner password credentials
- [ ] Authorization code without PKCE

*Answer:* Client credentials. No user is involved, so the service authenticates as itself.
