> ## 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.

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

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](/documentation/platform/pki/code-signing/signers) created by your Product Admin
* [Active signing access](/documentation/platform/pki/code-signing/approvals#access-lifecycle) (if an approval policy is attached)
* A [machine identity](/documentation/platform/identities/machine-identities) added to the Signer
* The Infisical [PKCS#11 module](/documentation/platform/pki/code-signing/pkcs11-module) 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.
</Note>

For the full set of options, see the [PKCS#11 module configuration reference](/documentation/platform/pki/code-signing/pkcs11-module#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).
</Note>

## 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**.
</Note>

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.

<AccordionGroup>
  <Accordion title="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>

  <Accordion title="APK signature scheme v2/v3 not applied">
    Use `apksigner` (not `jarsigner`) for APK signing. Only `apksigner` applies v2/v3 APK signature schemes.
  </Accordion>
</AccordionGroup>

## What's Next?

<CardGroup cols={2}>
  <Card title="Sign JARs" icon="java" href="/documentation/platform/pki/guides/code-signing/jarsigner">
    Sign Java artifacts with jarsigner
  </Card>

  <Card title="Sign Windows Binaries" icon="windows" href="/documentation/platform/pki/guides/code-signing/osslsigncode">
    Sign Windows executables with osslsigncode
  </Card>
</CardGroup>
