Documentation

Server 3.x

Admin API#

WORK IN PROGRESS

We provide an API that can be used by administrators to create and destroy VPN configurations for users. This can be useful when organizations want to provision managed devices with a VPN configuration, without having their users manually configure the VPN.

The API can be used to obtain WireGuard or OpenVPN configuration files that are ready to use with the official OpenVPN and WireGuard VPN clients. There would be no need to use the eduVPN or Let’s Connect! applications in this scenario.

NOTE: this is a Preview Feature!

Configuration#

The API is disabled by default, but it is easy to enable.

$ sudo /usr/libexec/vpn-user-portal/generate-secrets --admin-api

By default, the API is only accessible from localhost in order to avoid anyone accessing the API from the network.

You can modify /etc/httpd/conf.d/vpn-user-portal.conf on Fedora/EL, or /etc/apache2/conf-available/vpn-user-portal.conf on Debian/Ubuntu. Set the Require ip option under <Files admin-api.php> to the IP address(es) from which you want to access the API. If your vpn-user-portal.conf does not contain anything related to the “Admin API”, make sure the following parts are added:

Alias ${VPN_APP_ROOT}/admin/api       /usr/share/vpn-user-portal/web/admin-api.php

<Directory /usr/share/vpn-user-portal/web>

    ...

    <Files admin-api.php>
        <RequireAny>
            Require local
            # Add the IP address(es) of your system(s) that need to access the
            # Admin API here
            #Require ip 192.0.2.0/24
            #Require ip 2001:db::/32
        </RequireAny>
    </Files>

    ...

</Directory>

NOTE: if you modify vpn-user-portal.conf file, on Debian/Ubuntu, you MAY be notified during upgrades of vpn-user-portal about a changed configuration file. In that case choose to KEEP your current configuration file, or manually merge your changes!

Do NOT forget to restart Apache after modifying the files.

In order to use the API, the secret you need can be found in /etc/vpn-user-portal/keys/admin-api.key after generating it which was done above. Use this value in the Authorization (Bearer) header. See the examples below.

API Calls#

See the table below for supported API calls.

Method URL Description Since
GET /connected_users Show a list of connected users for each profile 3.5.1
GET /connection_list Show a list of all connections per profile 3.5.3
GET /users List all users 3.5.2
GET /disabled_users List all disabled users 3.5.2
GET /user_configuration_list Get list of all configurations of user 3.5.4
POST /create Create a VPN profile configuration for user 3.0.6
POST /destroy Delete user account and all configurations 3.0.6
POST /disable_user Disable user account (and disconnect user) 3.5.1
POST /enable_user Enable user account 3.5.1
POST /delete_connection Delete a connection 3.5.3
POST /delete_user_authorizations Delete all OAuth authorizations of user 3.5.4

Connected Users#

Get a list of users currently connected to the VPN (per profile).

Request#

$ curl \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/connected_users"

Response#

NOTE: in vpn-user-portal >= 3.5.2 the response is now wrapped in the object connected_users, in 3.5.1 it was not!

The following example output shows two profiles, students and employees. The students profile has three connected users. The employees profile has no connected users. If the same user is connected multiple times to the same profile that user is only listed once.

{
    "connected_users": {
        "employees": [],
        "students": [
            "ellis",
            "remi",
            "charlie"
        ]
    }
}

Connection List#

Get a list of all connections to a server (per profile).

Request#

$ curl \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/connection_list"

Response#

{
    "connection_list": {
        "default": [
            {
                "auth_key": null,
                "connection_id": "z/2CtDHH/tJBosty+bjF7JhCZ8K8ulqqi3/ODAfzDRI=",
                "display_name": "iPhone",
                "ip_list": [
                    "10.146.176.4",
                    "fdee:1ead:29e8:22a2::4"
                ],
                "user_id": "ellis",
                "vpn_proto": "wireguard"
            },
            {
                "auth_key": "hVYT4GwEXlhOqH0jLq8pIzTT-D2D-cr3UzllM9BG4Gg",
                "connection_id": "T4q3RbSw9uDPciZeUEBlVPoS4ubKRj6E/T7AqKR5MQ8=",
                "display_name": "org.eduvpn.app.ios",
                "ip_list": [
                    "10.146.176.2",
                    "fdee:1ead:29e8:22a2::2"
                ],
                "user_id": "remi",
                "vpn_proto": "wireguard"
            }
        ]
    }
}

The above shows that there are two users connected to the default profile, ellis and remi.

The connection_id field indicates the “Common Name” of the certificate (for OpenVPN) or the public key (for WireGuard).

If you want to filter the result list, e.g. only show connections for user foo to profile bar, you can use jq:

$ curl ... | jq '.connection_list.bar[]|select(.user_id == "foo")

If you want to see all connections for a particular user:

$ curl ... | jq '.connection_list.[][]|select(.user_id == "foo")

If you want to extract the connection_id for all connections of a particular user to any profile:

$ curl ... | jq -r '.connection_list.[][]|select(.user_id == "foo").connection_id

The -r flag returns the “raw” response, so the connection_id values are not quoted anymore.

List All Users#

Get a list of all users known to the VPN server.

Request#

$ curl \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/users"

Response#

{
    "users": [
        "ellis",
        "remi",
        "charlie"
    ]
}

List Disabled Users#

Get a list of all disabled users known to the VPN server.

Request#

$ curl \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/disabled_users"

Response#

{
    "disabled_users": [
        "charlie"
    ]
}

List Configurations of User#

Parameter Required Value(s)
user_id Yes The user account for which to list configurations

Request#

$ curl \
    --url-query "user_id=foo" \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/user_configuration_list"

Response#

{
  "user_configuration_list": [
    {
      "connection_id": "eoJu5pqw3Kcz/5ezTJZfw75/mEE4jawY+lcF4XtRAzg=",
      "profile_id": "default",
      "display_name": "Foo Bar",
      "auth_key": null,
      "expires_at": "2026-12-14T11:48:06+00:00",
      "vpn_proto": "wireguard"
    }
  ]
}

Create#

Create a VPN configuration for a particular user (and profile). The /create call will transparently create the user if necessary

Parameter Required Value(s)
user_id Yes The user for which to create the configuration
display_name No How to list the created configuration in the portal (default: Admin API)
profile_id Yes The profile_id of the VPN profile to create a configuration for
prefer_tcp No Prefer connecting over TCP to the server. Either yes or no. Defaults to no

Request#

Obtain a configuration file for the “Employees” profile (employees) for the user foo:

$ curl \
    --data-urlencode "user_id=foo" \
    --data-urlencode "profile_id=employees" \
    --data-urlencode "display_name=Admin API Example Config" \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/create"

Destroy#

Remove the VPN configurations of a particular user and delete their account.

Parameter Required Value(s)
user_id Yes The user for which to delete the configuration(s) and delete their account

TODO: should we also require profile_id to only delete config of certain profile?

TODO: should we also allow for not deleting the user account? if the answer to the above question is YES then we should probably not (always) delete the user account

Request#

$ curl \
    --data-urlencode "user_id=foo" \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/destroy"

Disable User#

Disable a user account and disconnect all active connections.

Parameter Required Value(s)
user_id Yes The user account to disable

Request#

$ curl \
    --data-urlencode "user_id=foo" \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/disable_user"

Enable User#

Enable a user account.

Parameter Required Value(s)
user_id Yes The user account to enable

Request#

$ curl \
    --data-urlencode "user_id=foo" \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/enable_user"

Delete Connection#

Delete a connection.

Parameter Required Value(s)
user_id Yes The user account to which the connection belongs
connection_id Yes The connection identifier

The connection_id field references the Common Name (CN) for OpenVPN and the public key for WireGuard.

Request#

$ curl \
    --data-urlencode "user_id=foo" \
    --data-urlencode "connection_id=z/2CtDHH/tJBosty+bjF7JhCZ8K8ulqqi3/ODAfzDRI=" \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/delete_connection"

Delete OAuth Authorizations#

This call will delete all OAuth authorizations for the specified user. It will NOT do anything else, i.e. not delete configurations or disconnect VPN users. Use the other API calls for this.

Parameter Required Value(s)
user_id Yes The user account for which to delete the OAuth Authorizations

Request#

$ curl \
    --data-urlencode "user_id=foo" \
    -H "Authorization: Bearer abcdefgh" \
    "https://vpn.example.org/vpn-user-portal/admin/api/v1/delete_user_authorizations"

VPN Client#

We’ll describe how to configure VPN clients with these configuration files.

Windows#

Complete documentation on how to setup Windows with WireGuard to have VPN enabled before user authentication can be found here.

You can deploy the configuration file and MSI through AD/GPO and enable the service as documented.

macOS#

Probably using this.