ansible / ansible/awx-plugins

Add OAuth2 Client Credentials Token credential plugin

Open
#184 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
9
Forks
41
Avg merge
8d 14h
Merged PRs (30d)
2

Description

## Summary

Add a new external credential plugin that fetches a short-lived bearer token using the OAuth 2.0 `client_credentials` grant. This enables authentication with services that require OAuth2 tokens without storing long-lived credentials.

## Motivation

Azure DevOps has deprecated Personal Access Tokens (PATs) and SSH keys for service-to-service authentication in favour of Microsoft Entra ID (Azure AD) service principals. There is currently no built-in credential plugin to acquire OAuth2 tokens at runtime for use as SCM credentials.

This pattern is not limited to Azure DevOps. Any service that accepts bearer tokens obtained via the `client_credentials` grant can benefit, including:

- **Microsoft Entra ID** for Azure DevOps repositories
- **Keycloak** for on-premises services
- **Okta** and **Auth0** for SaaS integrations
- Any OAuth2-compliant identity provider

## Proposed solution

A new credential plugin (`oauth2_client_credentials`) that:

1. Accepts `token_url`, `client_id`, and `client_secret` as input fields.
2. Accepts an optional `scope` as metadata (set when linking to a target credential).
3. Calls the token endpoint using the `client_credentials` grant on every credential resolution.
4. Returns the `access_token` from the token response.

### Use case: Azure DevOps project sync

1. Admin creates an Entra ID App Registration with a client secret.
2. Admin adds the Service Principal to the ADO organisation with Basic access.
3. An "OAuth2 Client Credentials Token Lookup" credential is created with the Entra token endpoint, client ID, and client secret.
4. A Source Control credential is created with `x-token` as the username and its password field linked to the OAuth2 credential (scope: `499b84ac-1321-427f-aa17-267ca6975798/.default`).
5. Project sync automatically resolves a fresh Entra token on every run.

### Use case: generic OAuth2 provider (e.g. Keycloak)

The same plugin works with any compliant OAuth2 provider. Only the `token_url` and optionally `scope` differ.

## Files to change

- `src/awx_plugins/credentials/oauth2_client_credentials.py` (new plugin module)
- `tests/oauth2_client_credentials_test.py` (unit tests)
- `pyproject.toml` (entry point and optional dependency)
- `tests/importable_test.py` (add to entry point smoke tests)
- `docs/spelling_wordlist.txt` (add Entra, Keycloak if needed)

## Dependencies

- `requests` (already a dependency of several existing plugins)
- `awx_plugins.interfaces` (for `gettext_noop`)

Contributor guide

Open the contributing guide

Research direction

Start with the proposed module at src/awx_plugins/credentials/oauth2_client_credentials.py and inspect the entry point configuration in pyproject.toml. Add unit coverage in tests/oauth2_client_credentials_test.py and include the plugin in tests/importable_test.py; done means resolving a credential requests a client-credentials token and returns its access_token, with the optional scope supported.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
authentication
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.