# Deploy Keys API Reference

Deploy keys are SSH keys that grant read-only or read-write access to a single repository. They are commonly used for CI/CD pipelines and automated deployment systems.

---

## Endpoints

### List Deploy Keys

```
GET /repos/{owner}/{repo}/keys
```

**Path Parameters:**

| Parameter | Type   | Required | Description        |
|-----------|--------|----------|--------------------|
| owner     | string | yes      | Repository owner   |
| repo      | string | yes      | Repository name    |

**Query Parameters:**

| Parameter   | Type    | Description                          |
|-------------|---------|--------------------------------------|
| key_id      | integer | Filter by key ID                     |
| fingerprint | string  | Filter by key fingerprint            |
| page        | integer | Page number (1-based)                |
| limit       | integer | Page size (default varies by config) |

```bash
# List all deploy keys
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/keys" \
  -H "Authorization: token ${FORGEJO_PAT}"

# Filter by fingerprint
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/keys?fingerprint={fingerprint}" \
  -H "Authorization: token ${FORGEJO_PAT}"

# Paginated
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/keys?page=1&limit=20" \
  -H "Authorization: token ${FORGEJO_PAT}"
```

### Add Deploy Key

```
POST /repos/{owner}/{repo}/keys
```

**Path Parameters:**

| Parameter | Type   | Required | Description        |
|-----------|--------|----------|--------------------|
| owner     | string | yes      | Repository owner   |
| repo      | string | yes      | Repository name    |

**CreateKeyOption (JSON body):**

| Field     | Type    | Required | Description                                            |
|-----------|---------|----------|--------------------------------------------------------|
| key       | string  | yes      | SSH public key content (e.g., `ssh-rsa AAAA...`)       |
| title     | string  | yes      | Key name/title for identification                      |
| read_only | boolean | no       | If true, key can only pull (default: **false**)        |

```bash
# Add a read-only deploy key
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/keys" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "CI Deploy Key",
    "key": "ssh-rsa AAAA...",
    "read_only": true
  }'

# Add a read-write deploy key
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/keys" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "CD Deploy Key",
    "key": "ssh-ed25519 AAAA...",
    "read_only": false
  }'
```

### Get Deploy Key by ID

```
GET /repos/{owner}/{repo}/keys/{id}
```

**Path Parameters:**

| Parameter | Type    | Required | Description        |
|-----------|---------|----------|--------------------|
| owner     | string  | yes      | Repository owner   |
| repo      | string  | yes      | Repository name    |
| id        | integer | yes      | Deploy key ID      |

```bash
curl -s "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/keys/{key_id}" \
  -H "Authorization: token ${FORGEJO_PAT}"
```

### Delete Deploy Key

```
DELETE /repos/{owner}/{repo}/keys/{id}
```

**Path Parameters:**

| Parameter | Type    | Required | Description        |
|-----------|---------|----------|--------------------|
| owner     | string  | yes      | Repository owner   |
| repo      | string  | yes      | Repository name    |
| id        | integer | yes      | Deploy key ID      |

Returns **204 No Content** on success.

```bash
curl -s -X DELETE "${FORGEJO_URL}/api/v1/repos/{owner}/{repo}/keys/{key_id}" \
  -H "Authorization: token ${FORGEJO_PAT}"
```

---

## DeployKey Response Object

| Field       | Type       | Description                                              |
|-------------|------------|----------------------------------------------------------|
| id          | integer    | Unique key ID                                            |
| key         | string     | SSH public key content                                   |
| url         | string     | API URL for this deploy key                              |
| title       | string     | Key name/title                                           |
| fingerprint | string     | SSH key fingerprint (e.g., `SHA256:abc...`)              |
| created_at  | string     | Creation timestamp (ISO 8601)                            |
| read_only   | boolean    | Whether the key is read-only                             |
| repository  | Repository | Repository object this key is associated with            |

**Example response:**

```json
{
  "id": 17,
  "key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...",
  "url": "https://{FORGEJO_HOST}/api/v1/repos/{owner}/{repo}/keys/{key_id}",
  "title": "CI Deploy Key",
  "fingerprint": "SHA256:aBcDeFgHiJkLmNoPqRsTuVwXyZ...",
  "created_at": "2024-06-15T10:30:00Z",
  "read_only": true,
  "repository": {
    "id": 42,
    "name": "{repo}",
    "full_name": "{owner}/{repo}"
  }
}
```

---

## Common Patterns

### CI/CD Setup: Add a Read-Only Key for Cloning

```bash
# Generate a key pair for CI (do this once, store private key in CI secrets)
ssh-keygen -t ed25519 -f ci_deploy_key -N "" -C "ci@{org}"

# Add the public key to the repo
PUBLIC_KEY=$(cat ci_deploy_key.pub)
curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/keys" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d "{
    \"title\": \"CI Pipeline - $(date +%Y-%m-%d)\",
    \"key\": \"${PUBLIC_KEY}\",
    \"read_only\": true
  }"
```

### Rotate Deploy Keys

```bash
OWNER="{owner}"
REPO="{repo}"

# 1. List current keys
KEYS=$(curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/keys" \
  -H "Authorization: token ${FORGEJO_PAT}")

echo "Current keys:"
echo "$KEYS" | jq '.[] | {id, title, fingerprint, created_at}'

# 2. Generate new key
ssh-keygen -t ed25519 -f new_deploy_key -N "" -C "deploy@{org}"
NEW_PUBLIC_KEY=$(cat new_deploy_key.pub)

# 3. Add new key
NEW_KEY=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/keys" \
  -H "Authorization: token ${FORGEJO_PAT}" \
  -H "Content-Type: application/json" \
  -d "{
    \"title\": \"Deploy Key (rotated $(date +%Y-%m-%d))\",
    \"key\": \"${NEW_PUBLIC_KEY}\",
    \"read_only\": true
  }")

echo "New key added: $(echo "$NEW_KEY" | jq '.id')"

# 4. Update CI secrets with new private key (do this in your CI system)

# 5. Delete old key
OLD_KEY_ID=$(echo "$KEYS" | jq '.[0].id')
curl -s -X DELETE "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/keys/${OLD_KEY_ID}" \
  -H "Authorization: token ${FORGEJO_PAT}"
echo "Old key ${OLD_KEY_ID} deleted."
```

### Audit Deploy Keys Across Repos

```bash
# List deploy keys for multiple repos
for REPO in {repo1} {repo2} {repo3}; do
  echo "=== ${REPO} ==="
  curl -s "${FORGEJO_URL}/api/v1/repos/${OWNER}/${REPO}/keys" \
    -H "Authorization: token ${FORGEJO_PAT}" \
    | jq '.[] | {id, title, fingerprint, read_only, created_at}'
done
```

---

## Gotchas

- **Each deploy key can only be used on ONE repository.** If you try to add the same SSH public key to a second repository, the API will return an error. Generate a separate key pair for each repository.
- **`read_only` defaults to `false`** — if you omit this field, the key will have read-write access. Always explicitly set `read_only: true` for CI/CD keys that only need to clone.
- Deploy keys authenticate at the SSH/git transport level. They do not grant access to the Forgejo API. Use personal access tokens or OAuth2 tokens for API access.
- Deleting a deploy key is immediate and cannot be undone. Any CI/CD pipelines using that key will immediately lose access.
