---
title: PingFederate plugin developer guide
description: This guide is to help developers build a PingFederate plugin using the Software Development Kit (SDK). It explains what a plugin is, how the pieces fit together, what a plugin project looks like on disk, and how to unit test one. It's meant to be read alongside example plugins in the <pingfed-install>/pingfederate/sdk/examples/ directory. Pick the example closest to what you want to build and follow along.
component: pingfederate
version: 13.0
page_id: pingfederate:sdk_developers_guide:pf_plugin_developer_guide
canonical_url: https://docs.pingidentity.com/pingfederate/13.1/sdk_developers_guide/pf_plugin_developer_guide.html
llms_txt: https://docs.pingidentity.com/pingfederate/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
superseded_by: https://docs.pingidentity.com/pingfederate/13.1/sdk_developers_guide/pf_plugin_developer_guide.html
section_ids:
  what-is-a-plugin: What is a plugin?
  how-the-pieces-fit-together: How the pieces fit together
  project-layout: Project layout
---

# PingFederate plugin developer guide

This guide is to help developers build a PingFederate plugin using the Software Development Kit (SDK) *(tooltip: \<div class="paragraph">
\<p>A set of tools that allows a developer to build a custom application that integrates with or connects to a platform or service.\</p>
\</div>)*. It explains what a plugin is, how the pieces fit together, what a plugin project looks like on disk, and how to unit test one. It's meant to be read alongside example plugins in the `<pingfed-install>/pingfederate/sdk/examples/` directory. Pick the example closest to what you want to build and follow along.

## What is a plugin?

A PingFederate plugin is a Java class that implements one of the interfaces the SDK defines, such as `PasswordCredentialValidator`, `IdpAuthenticationAdapterV2`, and `TokenGenerator`. Each interface represents an extension point, which is a place where PingFederate calls out to your code instead of, or in addition to, its built-in behavior.

You compile your class into a jar, tell PingFederate which class implements which interface, and drop the jar into the server. PingFederate discovers it at startup and makes it available in the admin console alongside its built-in options.

Two things make this simpler than it sounds:

* The SDK is provided, not bundled

  Your `pom.xml` depends on `pingfederate-sdk` with `provided` scope. That means the interfaces and helper classes are available while you're writing code, but they're not packaged into your jar. The running server already has them. Your jar only needs to contain your own classes.

* Discovery is just a text file

  PingFederate finds your plugin class through a small file under `PF-INF/` in your jar, named after the plugin type, containing the fully-qualified class name that implements it. Nothing more elaborate than that.

## How the pieces fit together

Building a plugin involves five steps:

1. Pick the extension point.

   Choose the SDK interface matching what you want to add, such as a password validator, an identity provider (IdP) *(tooltip: \<div class="paragraph">
   \<p>A service that manages identity information and provides authentication services to relying clients or SPs within a federated or distributed network.\</p>
   \</div>)* adapter, a token generator, or a data store. Each subdirectory in `examples/` is a working implementation of one extension point. Find the closest match and use it as your starting point.

2. Implement the interface.

   Every plugin type requires two methods no matter what it does:

   * `configure(Configuration)`: Where PingFederate hands you the admin settings.

   * `getPluginDescriptor()`: Where you describe the plugin back to PingFederate.

     Beyond these, you implement whatever methods the specific interface requires, plus any optional companion interfaces for extra capabilities, such as a password validator that also supports password reset.

3. Describe the admin GUI.

   Inside `getPluginDescriptor()`, build a `GuiConfigDescriptor` with text fields such as `TextFieldDescriptor` or `CheckBoxFieldDescriptor`. This declares the attribute contract, the set of attribute names your plugin promises to produce for whatever consumes them downstream. It also allows an admin to configure your plugin from the admin console.

4. Add the deployment descriptor.

   Create the `src/main/resources/PF-INF/` file described above as a static resource.

5. Build and deploy.

   `mvn clean install` produces the jar. Copy the jar to `<pingfed_install>/pingfederate/server/default/deploy` and restart the server. Your plugin now shows up in the admin console under the display name your gave it in `getPluginDescriptor()`.

### Project layout

Every example plugin in the `<pingfed-install>/pingfederate/sdk/examples/` directory follows the same layout.

The following is the layout for the `dynamic-client-registration` plugin, which also includes unit tests:

```shell
dynamic-client-registration/
├── pom.xml                  # internal build, used only inside this source tree
├── pom-example.xml          # the build customers actually use; renamed to
│                            #   pom.xml when the SDK distribution is assembled
├── README-example.md        # build/deploy instructions for this example
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/pingidentity/clientregistration/
│   │   │       └── SoftwareStatementValidatorPlugin.java
│   │   │                    # the plugin class — implements an SDK interface
│   │   └── resources/
│   │       └── PF-INF/
│   │           └── dynamic-client-registration
│   │                    # the deployment descriptor: one line, the
│   │                    #   implementing class's fully-qualified name.
│   │                    #   Checked in and hand-maintained — see "The
│   │                    #   deployment descriptor" below
│   └── test/
│       ├── java/
│       │   └── com/pingidentity/clientregistration/
│       │       ├── SoftwareStatementValidatorPluginTest.java
│       │       │            # a JUnit test for the plugin
│       │       └── TestTrustedCAAccessorService.java
│       │                    # a test-only service implementation — see
│       │                    #   "Unit testing" below
│       └── resources/
│           └── META-INF/
│               └── services/
│                   └── com.pingidentity.sdk.internal.services.interfaces.TrustedCAAccessorService
│                            # registers the test implementation above
└── target/                  # build output — jar, compiled classes; not checked in
```

A plugin with no unit tests is simpler. Those include only `pom.xml`, `pom-example.xml`, `README-example.md`, the plugin class, and its `PF-INF/` descriptor. The `src/test` directory only appears when an example ships with test.
