> ## Documentation Index
> Fetch the complete documentation index at: https://infisical.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign Android APKs with apksigner

> Use the Infisical PKCS#11 module to sign Android APK and AAB files with apksigner.

> [!NOTE]
>
> This guide assumes your Product Admin has already created a [Signer](https://infisical.com/docs/documentation/platform/pki/code-signing/signers) and assigned you to it. If the signer has an approval policy, you'll also need [active access](https://infisical.com/docs/documentation/platform/pki/code-signing/approvals.md#access-lifecycle) before signing.

Sign Android APK and Android App Bundle (AAB) files using `apksigner` with the Infisical PKCS#11 module. Since `apksigner` is a Java-based tool, it uses the same SunPKCS11 provider approach as jarsigner.

## Prerequisites

* A [Signer](https://infisical.com/docs/documentation/platform/pki/code-signing/signers) created by your Product Admin
* [Active signing access](https://infisical.com/docs/documentation/platform/pki/code-signing/approvals.md#access-lifecycle) (if an approval policy is attached)
* A [machine identity](https://infisical.com/docs/documentation/platform/identities/machine-identities.md) added to the Signer
* The Infisical [PKCS#11 module](https://infisical.com/docs/documentation/platform/pki/code-signing/pkcs11-module.md) installed and configured
* Android SDK Build Tools 30.0.0 or later (includes `apksigner`)

## Step 1: Set up authentication

Configure the Infisical PKCS#11 module with your machine identity credentials. Without this, the signing commands below fail with an auth error.

Create `/etc/infisical/pkcs11.conf` (or set `INFISICAL_CONFIG` to point elsewhere):

```yaml theme={"dark"}
auth:
  method: universal-auth
  universal_auth:
    client_id: "<machine-identity-client-id>"
    client_secret: "<machine-identity-client-secret>"

signer:
  id: "<signer-id>"
```

You can also pass the credentials via environment variables:

```bash theme={"dark"}
export INFISICAL_UNIVERSAL_AUTH_CLIENT_ID="<machine-identity-client-id>"
export INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET="<machine-identity-client-secret>"
```

> [!NOTE]
>
> Environment variables override values from the config file.

For the full set of options, see the [PKCS#11 module configuration reference](https://infisical.com/docs/documentation/platform/pki/code-signing/pkcs11-module.md#configuration).

## Step 2: Create the SunPKCS11 provider configuration

Create a configuration file for Java's SunPKCS11 provider. Save it as `infisical-pkcs11.cfg`:

```
name = Infisical
library = /usr/local/lib/libinfisical-pkcs11.so
```

> [!NOTE]
>
> On macOS, use `.dylib`. On Windows, use `.dll`. If you have multiple signers and need a specific one, add `slot = 0` (replace with the correct slot index).

## Step 3: Sign an APK

Use `apksigner` with the PKCS#11 provider:

```bash theme={"dark"}
apksigner sign \
  --ks NONE \
  --ks-type PKCS11 \
  --provider-class sun.security.pkcs11.SunPKCS11 \
  --provider-arg infisical-pkcs11.cfg \
  --ks-key-alias "release-signer" \
  --out app-release-signed.apk \
  app-release-unsigned.apk
```

> [!NOTE]
>
> * `--ks NONE`: Required when using PKCS#11 (no file-based keystore).
> * `--ks-type PKCS11`: Tells apksigner to use the PKCS#11 provider.
> * `--ks-key-alias`: The signer name (token label in PKCS#11).
> * `--out`: Writes the signed APK to a new file. Without this flag, `apksigner` modifies the APK **in place**.

When prompted for a keystore password, press Enter (the module authenticates using the credentials from your environment variables or config file).

### Signing an Android app bundle (AAB)

For AAB files, use `jarsigner` instead of `apksigner` since AAB signing follows the JAR signing format:

```bash theme={"dark"}
jarsigner \
  -keystore NONE \
  -storetype PKCS11 \
  -addprovider SunPKCS11 \
  -providerArg infisical-pkcs11.cfg \
  -sigalg SHA256withRSA \
  app-release.aab \
  "release-signer"
```

## Step 4: Verify the signature

Verify the signed APK. If you signed in place (without `--out`), verify the same file. If you used `--out`, verify the output file:

```bash theme={"dark"}
apksigner verify --verbose app-release-signed.apk
```

The output confirms the APK signature is valid:

```
Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Verified using v3 scheme (APK Signature Scheme v3): true
```

## CI/CD integration

Example for a Gradle-based Android project in CI:

```bash theme={"dark"}
export INFISICAL_UNIVERSAL_AUTH_CLIENT_ID="${INFISICAL_CLIENT_ID}"
export INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET="${INFISICAL_CLIENT_SECRET}"
export INFISICAL_CONFIG="/path/to/pkcs11.conf"

# Build unsigned APK
./gradlew assembleRelease

# Sign with Infisical
apksigner sign \
  --ks NONE \
  --ks-type PKCS11 \
  --provider-class sun.security.pkcs11.SunPKCS11 \
  --provider-arg infisical-pkcs11.cfg \
  --ks-key-alias "release-signer" \
  --ks-pass pass:"" \
  --out app-release-signed.apk \
  app/build/outputs/apk/release/app-release-unsigned.apk

# Verify
apksigner verify --verbose app-release-signed.apk
```

## Troubleshooting

For any issue, enable debug logging in your config file (`"log_level": "debug"`, `"log_file": "/tmp/infisical-pkcs11.log"`) to get detailed output.

> [accordion] Failed to load signer or key alias not found
>
> Ensure the `--provider-class` is `sun.security.pkcs11.SunPKCS11`, the `--provider-arg` points to a valid config file, and the `--ks-key-alias` matches your signer name exactly.

> [accordion] APK signature scheme v2/v3 not applied
>
> Use `apksigner` (not `jarsigner`) for APK signing. Only `apksigner` applies v2/v3 APK signature schemes.

## What's next?

> [card] [Sign JARs](https://infisical.com/docs/documentation/platform/pki/guides/code-signing/jarsigner.md)
>
> Sign Java artifacts with jarsigner

> [card] [Sign Windows Binaries](https://infisical.com/docs/documentation/platform/pki/guides/code-signing/osslsigncode.md)
>
> Sign Windows executables with osslsigncode


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.