OAuth Authentication

Modified on Tue, 14 Jul at 11:37 AM

Use OAuthAuthenticator (maltego.model.oauth.OAuthAuthenticator) when a transform needs the user to authenticate against a third-party API in the Maltego client. The client handles the browser-based login flow, while the SDK registers the authenticator, enables OAuthMiddleware, and exposes the access token to the transform through settings[OAUTH.access_token_input].

**Client availability:** OAuth-authenticated transforms are currently supported in Maltego Graph Desktop only. Maltego Graph Browser does not currently run the OAuth flow for a custom transform server.

Configuring an authenticator

Create one OAuthAuthenticator per provider:

from maltego.model.oauth import OAuthAuthenticator

OAUTH = OAuthAuthenticator(
    name="acme-api",
    display_name="Log in to Acme",
    description="Authenticate against the Acme API",
    access_token_input="acme.token",
    access_token_pem_file_prefix="./oauth/acme",
    oauth_version="2.0",
    app_key="ACME_CLIENT_ID",
    app_secret="ACME_CLIENT_SECRET",
    authorization_url="https://example.com/oauth/authorize",
    access_token_endpoint="https://example.com/oauth/token",
    request_type_for_access_token="POST",
    icon="",
)

The main fields are:

  • access_token_input: the setting name your transform will read later.
  • access_token_pem_file_prefix: prefix for the PEM files used to protect the token material on disk.
  • oauth_version: use "2.0" for standard OAuth 2.0 providers and "1.0a" when the provider also requires request_token_endpoint.
  • app_key / app_secret: the client credentials for the provider.

Key material and development setup

The SDK expects the following files for the configured access_token_pem_file_prefix:

  • {prefix}_private.pem
  • {prefix}_public.pem

During setup(), the server copies MaltegoServerSettings.allow_regenerating_oauth_keys onto every registered authenticator and then calls generate_keys_if_needed(). For local development, enable automatic generation:

from maltego.server import MaltegoServerSettings

settings = MaltegoServerSettings(
    server_name="Acme Transforms",
    ns="acme",
    author="dev@acme.com",
    allow_regenerating_oauth_keys=True,
)

For deployed servers, generate or provision the PEM files ahead of time and keep them out of source control.

Registering an OAuth-protected transform

Attach the authenticator through register_transform(..., authenticator=...):

from typing import Any, Dict
from maltego.entities import Phrase
from maltego.server import register_transform

@register_transform(
    display_name="OAuth Test [Maltego Examples]",
    authenticator=OAUTH,
)
async def transform_oauth(
    input_entity: Phrase,
    settings: Dict[str, Any],
) -> Phrase:
    token = settings[OAUTH.access_token_input]
    if token is None:
        raise ValueError("settings[OAUTH.access_token_input] needs to be not None")
    return Phrase(token)

Passing authenticator=OAUTH does two things automatically:

  1. The server registers the authenticator for discovery.
  2. On the first authenticator, the server adds OAuthMiddleware and injects a hidden TransformSetting with auth=True and is_oauth=True.

What the user sees in Maltego

When a user runs the transform in the Maltego client:

  1. Maltego prompts the user to authenticate.
  2. The client completes the browser flow with the configured provider.
  3. The encrypted token is sent back to the server using the setting named by access_token_input.
  4. The SDK normalizes that value so your transform reads it as settings[OAUTH.access_token_input].

Making authenticated API calls

Once the token is available, use it like any other transform setting:

from typing import Any, Dict
from maltego.entities import Phrase
from maltego.model.context import MaltegoContext
from maltego.server import IntegrationClient, register_transform

client = IntegrationClient()

@register_transform(
    display_name="Acme profile",
    authenticator=OAUTH,
)
async def acme_profile(
    input_entity: Phrase,
    settings: Dict[str, Any],
    context: MaltegoContext,
) -> Phrase:
    token = settings[OAUTH.access_token_input]
    if token is None:
        raise ValueError("OAuth token is required")

    response = await client.get(
        "https://api.example.com/me",
        context=context,
        headers={"Authorization": f"Bearer {token}"},
    )
    payload = response.json()
    return Phrase(payload["username"])

Where this fits in a transform server project

Keep the OAuthAuthenticator definition with the rest of your server-wide configuration, and place the protected transforms in modules under transforms/. The important runtime contract is the one shown above: after the client completes the login flow, the transform reads the injected token from settings[OAUTH.access_token_input].

OAuth vs server authentication

This page is about authenticating from your transform to a third-party API. If you need to protect your own transform server with JWT/OIDC, see the Authentication article.

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article