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

# Download Certificate

> Returns the caller's OpenVPN client profile for an organization, issuing one on first use.
If the caller already holds a certificate it is returned as-is and no licence is consumed, so this endpoint is safe to call repeatedly. Otherwise the platform runs the VPN configuration's `create_cert` command over SSH, stores the result and increments `used_licenses`.
Issuing a new certificate requires a VPN assigned to the organization, a `create_cert` entry in that VPN's `commands` map, and at least one free licence.


<Warning>
  **JavaScript only** — the auto-generated sample calls `res.json()`, which throws a
  `SyntaxError` because this endpoint returns an OpenVPN profile
  (`application/x-openvpn-profile`), not JSON. Use `res.text()` instead, as shown
  below. The cURL, Python, PHP, Go, Java and Ruby samples handle this correctly.
</Warning>

```js theme={null}
fetch('https://closedvpn.io/auth/download-certificate?org_id=YOUR_ORG_ID', {
  headers: { Authorization: 'Bearer YOUR_PAT' }
})
  .then(res => res.text())
  .then(profile => console.log(profile))
  .catch(err => console.error(err));
```

For a complete walkthrough — including how to strip the leading `# closedvpn-json`
metadata line and save the profile as a `.ovpn` file — see
[Creating a VPN Certificate](/closedvpn/create-vpn-cert).


## OpenAPI

````yaml GET /auth/download-certificate
openapi: 3.0.0
info:
  title: ClosedVPN API
  version: 1.1.0
  description: >
    API for managing authentication, organizations, members, VPN configurations,

    certificates and usage reporting for the ClosedVPN platform.


    The VPN capability previously delivered through the OneFirewall Application

    (`https://app.onefirewall.com/api/v1/vpn`) now runs on ClosedVPN and is
    served

    from `https://closedvpn.io`. The legacy OneFirewall VPN endpoints are
    deprecated

    and replaced by the operations documented here.


    Most endpoints require a Personal Access Token (PAT), sent as

    `Authorization: Bearer <pat>`. To obtain one, sign in through the magic link

    flow (`/auth/send-magic-link` then `/auth/verify-magic-link`, neither of
    which

    requires prior authentication) and then call `/auth/generate-pat`, or create
    the

    token from the Profile page in the web application. The plaintext token is
    shown

    only once and is stored as a bcrypt hash, so it cannot be recovered later.
  contact:
    name: OneFirewall Alliance
    url: https://closedvpn.io
    email: support@onefirewall.com
servers:
  - url: https://closedvpn.io
    description: Production server
security: []
tags:
  - name: Authentication
    description: Magic link sign-in, session validation and sign-out.
  - name: Profile
    description: Read and update the authenticated user's profile.
  - name: Personal Access Tokens
    description: Create, list and revoke Personal Access Tokens used for API access.
  - name: Organizations
    description: Create, update, list, select and delete organizations.
  - name: Members
    description: Add members to an organization, change their role and remove them.
  - name: VPN Certificates
    description: Issue and download the OpenVPN client profile for a member.
  - name: VPN Configurations
    description: Manage VPN server configurations and run their predefined commands.
  - name: VPN Exit Nodes
    description: List the VPN exit nodes available to the caller.
  - name: Statistics
    description: Connection status, traffic reporting and threat prevention metrics.
  - name: Notifications
    description: Read in-app notifications and mark them as read.
  - name: Activity Logs
    description: Retrieve the caller's recent activity.
paths:
  /auth/download-certificate:
    get:
      tags:
        - VPN Certificates
      summary: Download VPN certificate
      description: >
        Returns the caller's OpenVPN client profile for an organization, issuing
        one on first use.

        If the caller already holds a certificate it is returned as-is and no
        licence is consumed, so this endpoint is safe to call repeatedly.
        Otherwise the platform runs the VPN configuration's `create_cert`
        command over SSH, stores the result and increments `used_licenses`.

        Issuing a new certificate requires a VPN assigned to the organization, a
        `create_cert` entry in that VPN's `commands` map, and at least one free
        licence.
      operationId: downloadCertificate
      parameters:
        - name: org_id
          in: query
          required: true
          schema:
            type: string
            example: 60c72b2f5f1b2c001c8e4b1a
      responses:
        '200':
          description: >
            The OpenVPN client profile. The body is not a bare `.ovpn` file: the
            first line is a `# closedvpn-json` comment carrying the
            organization's exit nodes, followed by a blank line and then the
            profile itself. Strip or ignore that comment line if your client
            does not tolerate it.
          headers:
            Content-Disposition:
              schema:
                type: string
              description: Suggested filename for the downloaded profile
              example: attachment; filename="ClosedVPN-My Org.ovpn"
          content:
            application/x-openvpn-profile:
              schema:
                type: string
                description: OpenVPN configuration file
                example: >
                  # closedvpn-json
                  {"vpnExitNodes":[{"id":"60c72b2f5f1b2c001c8e4b2a","name":"Frankfurt
                  Node","location":"Frankfurt,
                  Germany","coordinates":[50.1109,8.6821]}]}


                  client

                  dev tun

                  proto udp

                  remote vpn-fra.closedvpn.io 1194

                  <ca>

                  -----BEGIN CERTIFICATE-----

                  -----END CERTIFICATE-----

                  </ca>
        '400':
          description: >
            `org_id` is missing, no VPN is assigned to the organization, or the
            VPN configuration has no `create_cert` command.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Organization ID is required
        '401':
          description: Unauthorized (invalid or missing PAT)
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Unauthorized
        '403':
          description: >-
            Forbidden (user not part of the organization or license limit
            reached)
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: >-
                      You’ve reached the maximum number of certificates. Please
                      acquire more licenses.
        '404':
          description: Organization or user not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Organization not found
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Server error
                  error:
                    type: string
                    example: Detailed error message
      security:
        - bearerAuth: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: PAT
      description: >
        Personal Access Token (PAT) passed in the Authorization header (e.g.,
        `Bearer <pat>`) for authenticated API requests. PATs are generated via
        `/auth/generate-pat` after authenticating through the magic link flow.

````