Documentation

Server 2.x

Version 2.x of eduVPN is End of Life (EOL). Switch to "Server 3.x" Documentation!

APIv2#

This document describes the now obsolete API provided by all Let’s Connect!/eduVPN services.

The API can be used by applications integrating with the VPN software, making it easier for users to start using the VPN.

Instance Discovery#

This document assumes you already have a FQDN to connect to, e.g. specified by the user, but in order to allow applications to create a list of VPN services available to the user to connect to, we also documented Instance Discovery.

Standards#

OAuth 2.0 is used to provide the API. The following documents are relevant for implementations and should be followed except when explicitly stated differently:

Implementing OAuth 2.0 correctly in native apps is not easy. There are a number of sample libraries available for various platforms that can be used as a basis:

With this library it is very important that you handle all standard OAuth “error” conditions regarding expired, invalid or revoked tokens.

Definitions#

A VPN service running at a particular domain is called an instance, e.g. demo.eduvpn.nl. An instance can have multiple profiles, e.g. employees and administrators.

API Discovery#

The OAuth and API endpoints can be discovered by requesting a JSON document (info.json) from the instance, based on the base_uri, e.g. demo.eduvpn.nl. As an example, here is the content of https://demo.eduvpn.nl/info.json:

{
    "api": {
        "http://eduvpn.org/api#2": {
            "api_base_uri": "https://demo.eduvpn.nl/portal/api.php",
            "authorization_endpoint": "https://demo.eduvpn.nl/portal/_oauth/authorize",
            "token_endpoint": "https://demo.eduvpn.nl/portal/oauth.php/token"
        }
    }
}

When fetching the info.json file, redirects, e.g. 301, 302, 303, MUST be followed.

Authorization Endpoint#

The authorization_endpoint is used to obtain an authorization code. The following query parameters MUST be specified on the authorization request:

The authorization request is then opened using the platform’s default browser. Eventually the redirect_uri is called where the initiating application can extract the authorization code.

All error conditions MUST be handled according to the OAuth specification(s).

Token Endpoint#

The token_endpoint is used to exchange the authorization code for an access and refresh token. It is also used to retrieve new access tokens when the current access token expires.

The application MUST reauthorize, i.e. throw away all tokens and send a new authorization request, when:

  1. The access token did not expire yet, but was rejected by the API endpoint;
  2. The access token expired, but obtaining a new one using the refresh token failed.

All error conditions MUST be handled according to the OAuth specification(s).

Using the API#

The API is pragmatic “REST”, keeping things as simple as possible without obsessing about the proper HTTP verbs. There are no PUT and DELETE requests. Only GET, to retrieve information without affecting the state of the service, and POST to modify the server state.

The requests always return application/json. The POST requests MUST be sent encoded as application/x-www-form-urlencoded.

The API can be used with the access tokens obtained using the OAuth flow as documented above. The following API calls are available:

All error conditions MUST be handled according to the OAuth specification(s).

API Calls#

Multi Language Support#

For the calls listed below, applications MUST check if the mentioned value is a string, or an object. In case of an object, the language best matching the application language SHOULD be chosen. If that language is not available, the application SHOULD fallback to en or en-US. If neither of those is available, it is up to the application to pick one it deems best.

An example:

"display_name": {
    "nl": "Internettoegang",
    "en-US": "Internet Access"
}

Date / Time Formats#

Any occurrence of data and/or time has the ISO 8601 format. It is used by the following API calls:

Profile List#

This call will show the available VPN profiles for this instance. This will allow the application to show the user which profiles are available.

$ curl -H "Authorization: Bearer abcdefgh" \
    https://demo.eduvpn.nl/portal/api.php/profile_list

The response looks like this:

{
    "profile_list": {
        "data": [
            {
                "display_name": "Internet Access",
                "profile_id": "internet",
                "default_gateway": true,
            }
        ],
        "ok": true
    }
}

NOTE: default_gateway is available since vpn-user-portal >= 2.3.0 and indicates whether the profile expects all client traffic to go over the VPN.

Create a Key Pair#

NOTE: an obtained key pair is valid for ALL profiles of a particular instance, so if an instance has multiple profiles, only one key pair is needed.

NOTE: on old(er) servers the display_name POST parameter is required, on up-to-date servers the parameter is ignored.

$ curl -H "Authorization: Bearer abcdefgh" \
    -d 'display_name=OAuth' https://demo.eduvpn.nl/portal/api.php/create_keypair

The call will create a certificate and private key and return them:

{
    "create_keypair": {
        "data": {
            "certificate": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
            "private_key": "-----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY-----"
        },
        "ok": true
    }
}

The certificate and the private key SHOULD be stored in the platform’s “key store” in such a way that the user can NOT export the private key.

In traditional OpenVPN client configuration files, the certificate would be placed in the <cert>...</cert> inline section, and the private key in the <key>...</key> section.

Profile Config#

Only get the profile configuration without certificate and private key.

$ curl -H "Authorization: Bearer abcdefgh" \
    "https://demo.eduvpn.nl/portal/api.php/profile_config?profile_id=internet"

The response will be an OpenVPN configuration file without the <cert> and <key> fields.

Starting from vpn-user-portal >= 2.1.1, an optional parameter remote_strategy can be specified that takes an integer. It determines which remote lines are returned as part of the generated configuration file. Value 0 takes the first UDP/TCP ports of the “normal” and “special” sets. Value 1 takes random ports from both the “normal” and “special” sets. Value 2 returns them all. The default is 1. Only change this if you know what you are doing! More on remote lines in the VPN configuration can be read here.

Check Certificate#

A call is available to check whether an already obtained certificate will be accepted by the VPN server. There are a number of reasons why this may not be the case:

The client MAY implement this call, but MAY also opt to attempt to connect and handle a connection rejection by attempting to obtain a new X.509 certificate / key using the /create_keypair call and retry the connection.

API call:

$ curl -H "Authorization: Bearer abcdefgh" \
    "https://demo.eduvpn.nl/portal/api.php/check_certificate?common_name=fd2c32de88c87d38df8547c54ac6c30e"

The common_name is the value of the X.509 certificate’s common name (CN) already in possession of the client.

The response looks like this:

{
    "check_certificate": {
        "data": {
            "is_valid": true
        },
        "ok": true
    }
}

Here, is_valid can also be false if the certificate won’t be accepted by the server. There MAY be a reason field that indicates the reason for the certificate to not be valid. The reason field is only there when is_valid is false:

{
    "check_certificate": {
        "data": {
            "is_valid": false,
            "reason": "certificate_missing"
        },
        "ok": true
    }
}

System Messages#

$ curl -H "Authorization: Bearer abcdefgh" \
    https://demo.eduvpn.nl/portal/api.php/system_messages

The application is able to access the system_messages endpoint to see if there are any notifications available.

All messages have the type notification. All messages have a date_time field containing the date the message was created.

An example response:

{
    "system_messages": {
        "data": [
            {
                "date_time": "2018-12-10T14:10:30Z",
                "message": "This is the MOTD!",
                "type": "notification"
            }
        ],
        "ok": true
    }
}

OAuth Client Registration#

A list of OAuth client registrations that are available for all installations can be found here.

Administrators MAY define additional OAuth clients in the /etc/vpn-user-portal/config.php configuration file.