Skip to main content

Project Authorizers Simplify Endpoint Security

· 4 min read

proxiML now supports Project Authorizers, letting you define an authorizer once per project and reuse it across every endpoint that needs it. Instead of re-entering the same API key or OIDC configuration in each endpoint job, create the authorizer a single time and reference it by ID when creating your endpoints.

How It Works​

With Endpoint Authorizers, the full authorizer definition had to be embedded in each endpoint job. Secure ten endpoints with the same identity provider, and you manage the same configuration in ten places -- and rotate it in ten places.

A Project Authorizer moves that definition up to the project level. You create it once, give it a name, and proxiML assigns it a stable ID. When you create an endpoint job, you reference the authorizer with the authorizer_id field and the endpoint enforces it exactly as before.

The same two authorizer types are available:

API Key -- Shared-secret access. Add one or more keys (up to 10), each with a Client ID label and a secret key value, and require callers to present the key via an Authorization: Bearer header.

OIDC -- JWT-based authentication for identity providers like Azure AD, Auth0, or Okta. Configure the issuer URL, expected audience, signing algorithms (e.g., RS256), JWKS URI, and optionally required JWT claims.

Because every endpoint points at the same definition, you update an authorizer in one place -- rotate an API key or change an OIDC setting -- and every endpoint that references it uses the updated definition. A few details worth knowing:

  • Authorizer names are unique within a project; endpoints reference the authorizer by its ID.
  • The authorizer type cannot be changed after creation, but the name, keys, and OIDC settings can be edited at any time.
  • An endpoint uses at most one authorizer: either a project authorizer via authorizer_id or an inline authorizer definition -- not both.
  • Inline per-endpoint authorizers continue to work, so existing endpoints are unaffected by this change.

Using the Web Platform​

Open your project and find the Project Authorizers section. Authorizers are listed with their name, type, and a summary of the details -- the client IDs for API Key authorizers or the issuer for OIDC. Use the Edit and Remove actions on each row to update or delete an authorizer.

Click Add to open the Add Project Authorizer form:

  • Name -- A name for the authorizer within the project.
  • Type -- Select API Key or OIDC.
  • API Key -- Add one or more key rows, each with a Client ID and a secret Key (up to 10). Use Generate API key to create a strong key automatically.
  • OIDC -- Configure the Issuer, Audience, and Algorithms (e.g., RS256), and optionally the JWKS URI and Required Claims (claim name plus allowed values).

The authorizer is saved when you click Submit. When editing an existing authorizer, the name and settings remain editable while the type is locked.

Using the SDK​

To create an API Key project authorizer and an endpoint that references it:

project = await proximl.projects.get_current() authorizer = await project.authorizers.create( name="shared-endpoint-authorizer", type="api_key", keys=[ dict(client_id="my-client", key="secret-key-value"), ], ) job = await proximl.jobs.create( name="Secure Endpoint", type="endpoint", gpu_type="rtx3090", gpu_count=1, endpoint=dict( start_command="python serve.py", authorizer_id=authorizer.id, ), )

To create an OIDC project authorizer and reference it from an endpoint:

authorizer = await project.authorizers.create(
name="oidc-authorizer",
type="oidc",
oidc={
"issuer": "https://login.microsoftonline.com/YOUR-TENANT-ID/v2.0",
"audience": "api://YOUR-CLIENT-ID",
"jwks_uri": "https://login.microsoftonline.com/YOUR-TENANT-ID/discovery/v2.0/keys",
"algorithms": ["RS256"],
"required_claims": {"scp": ["api.access"]},
},
)
job = await proximl.jobs.create(
name="OIDC Endpoint",
type="endpoint",
gpu_type="rtx3090",
gpu_count=1,
endpoint=dict(
start_command="python serve.py",
authorizer_id=authorizer.id,
),
)

Because the endpoints only store a reference, updating the authorizer updates every one of them -- for example, rotating a key in place:

await authorizer.edit(
keys=[
dict(client_id="my-client", key="new-secret-key-value"),
],
)
# Remove the authorizer when it is no longer needed
await project.authorizers.remove(authorizer.id)

Using the CLI​

The trainml CLI manages authorizers for your current project:

# List authorizers (ID, NAME, TYPE, UPDATED AT)
trainml project authorizer list

# Add an API Key authorizer -- prompts for the key with hidden input
trainml project authorizer add shared-authorizer --type api_key --client-id my-client

# Add an OIDC authorizer
trainml project authorizer add oidc-authorizer --type oidc \
--issuer https://login.microsoftonline.com/YOUR-TENANT-ID/v2.0 \
--audience api://YOUR-CLIENT-ID \
--algorithms RS256 \
--jwks-uri https://login.microsoftonline.com/YOUR-TENANT-ID/discovery/v2.0/keys \
--required-claims '{"scp": ["api.access"]}'

# Remove an authorizer by name or ID
trainml project authorizer remove shared-authorizer

See the Endpoint Authorizers announcement for details on the original per-endpoint feature.