This is a public Node.js Express server that hosts the API and website. It does all the client-facing non-VPN functionality like creating accounts, managing subscriptions, and hosting client certificates.
- Prerequisites
- Authentication
- Signup
- Download App
- Get User Certificate/Key
- Account Management
- Reset Password
- Subscription Management
- Diagnostic/Other APIs
- Error Responses
- Support
- Run the Main CloudFormation and all its prerequisites
- Initialize the database with Admin Server
- Creating and setting a
CURRENT_SOURCE_ID
with Admin Server
Requires Authentication
calls, require a session cookie from the POST /signin
endpoint, which takes either email/password or IAP receipt. If you sign in with a new IAP receipt, a user will be created if that receipt has not been used before.
If a session cookie expires or server returns 401, request a new cookie with /signin
.
Request
POST /signin
Name | Type | Description |
---|---|---|
email |
string |
Required User email. |
password |
string |
Required User password. |
Response
Set-Cookie: <Cookie with Expiration Time>
If you sign in with a new IAP receipt, a user will be created if that receipt has not been used before.
Request
POST /signin
Name | Type | Description |
---|---|---|
authtype |
string |
Required Must be either ios or android . |
authreceipt |
string |
Required Base64 encoded IAP receipt. |
partner |
string |
Partner campaign for affiliate referrals. Format is [Partner Code]-[Campaign ID] , e.g, acme-1 . Partner code and campaign ID should both be lowercase. If no campaign ID is provided, campaign will show up as (no campaign). |
Response
Set-Cookie: <Cookie with Expiration Time>
Request
GET /logout
Response
Redirects to /signin
Doing a POST /signin
with IAP receipt will automatically create a user. An IAP-Signup User is automatically assigned a certificate with source ID CURRENT_SOURCE_ID
.
Request
GET /signup
Name | Type | Description |
---|---|---|
refer |
string |
Referral code. |
Request
POST /signup
Name | Type | Description |
---|---|---|
email |
string |
Required Email to use to create the user. |
password |
string |
Required User password. Minimum 8 characters, maximum 50 characters. |
browser |
boolean |
Whether or not this request is made from a browser, instead of an API call. If true , after confirming email, user will be redirected to /signin . If false , confirming email will open tunnels://emailconfirmed to complete signup. Defaults to false . |
refer |
string |
Referral code. |
Response
Sends a confirmation email to the user to verify they own the email, with a link to /confirm-email
.
If browser
== true
Redirect to /signup-success
If browser
== false
{
code: 1,
message: "Email Confirmation Sent"
}
Asks user to check their email for a confirmation link.
Request
GET /signup-success
A user that confirmes their email is assigned a certificate with source ID CURRENT_SOURCE_ID
.
Request
GET /confirm-email
Name | Type | Description |
---|---|---|
email |
string |
Required Email to confirm. |
code |
string |
Required Code that confirms a user is the owner of an email address to complete email signup. |
browser |
boolean |
Whether or not /signup was done by browser or API. If true , redirects to /signin . If false , opens tunnels://emailconfirmed . Defaults to false . |
Response
Redirect to either /account or tunnels://emailconfirmed
Request
GET /resend-confirm-code
Request
POST /resend-confirm-code
Name | Type | Description |
---|---|---|
email |
string |
Required Email to resend confirmation code to. |
Response
Redirect to /signin
Request
Authentication Required
POST /convert-shadow-user
Name | Type | Description |
---|---|---|
newemail |
string |
Required Email to add to this user. |
newpassword |
string |
Required Password to add to this user. |
Response
Sends a confirmation email to the user to verify they own the email, with a link to /confirm-email
.
{
code: 1,
message: "Email Confirmation Sent"
}
Request
GET /clients
Request
GET /download-mac-app
Response
Redirects to download the Mac app. If multiple versions are being distributed, the version that this redirects to will be selected randomly at percentages configured by the Admin Dashboard.
Request
GET /download-mac-update
Response
Redirects to download the Mac update file. If multiple versions are being distributed, the version that this redirects to will be selected randomly at percentages configured by the Admin Dashboard.
Request
GET /download-mac-app
Response
Redirects to download the Windows app. If multiple versions are being distributed, the version that this redirects to will be selected randomly at percentages configured by the Admin Dashboard.
Request
GET /download-windows-update
Response
Redirects to download the Windows update file. If multiple versions are being distributed, the version that this redirects to will be selected randomly at percentages configured by the Admin Dashboard.
Request
Authentication Required
POST /get-key
Name | Type | Description |
---|---|---|
platform |
string |
Required Must be ios , android , windows , or mac |
Response
{
id: <User ID>,
b64: Base64 encoded client certificate
}
Request
Authentication Required
GET /account
Request
Authentication Required
Returns CSRF Token
GET /change-email
Request
Authentication Required
CSRF Token Required
POST /change-email
Name | Type | Description |
---|---|---|
_csrf |
string |
Required CSRF Token from GET /change-email |
currentPassword |
string |
Required User's current password. |
newEmail |
string |
Required User's new email. |
Response
Redirect to /account
Sends email to confirm
Request
Authentication Required
Returns CSRF Token
GET /change-password
Request
Authentication Required
CSRF Token Required
POST /change-password
Name | Type | Description |
---|---|---|
_csrf |
string |
Required CSRF Token from GET /change-password |
currentPassword |
string |
Required User's current password. |
newPassword |
string |
Required User's new password. Must be minimum 8 characters long, maximum 50 characters long. |
Response
Redirect to /account
Request
Authentication Required
GET /invoices
Request
Authentication Required
GET /invoices
Name | Type | Description |
---|---|---|
id |
string |
Required The ID of the invoice. |
Request
Authentication Required
GET /payment-methods
Request
Authentication Required
GET /add-new-card
Request
Authentication Required
POST /add-new-card
Name | Type | Description |
---|---|---|
source |
string |
Required Source ID returned from Stripe after user submits their card information. |
Response
Redirect to /payment-methods
Request
Authentication Required
POST /set-default-card
Name | Type | Description |
---|---|---|
cardId |
string |
Required Stripe cardID for the payment method to set as default. |
Response
{
message: "New default set successfully"
}
Request
Authentication Required
POST /delete-card
Name | Type | Description |
---|---|---|
cardId |
string |
Required Stripe cardID for the payment method to delete. |
Response
{
message: "Card deleted successfully"
}
Links to opt out of email are automatically generated on every email sent to users, and placed at the bottom of every email. Authentication is not required to opt-out of emails, because someone may receive
Request
GET /do-not-email
Name | Type | Description |
---|---|---|
email |
string |
Required Email to opt-out. |
code |
string |
Required Code for opting out of emails. |
Request
POST /do-not-email
Name | Type | Description |
---|---|---|
email |
string |
Required Email to opt-out. |
code |
string |
Required Code for opting out of emails. |
Response
Redirect to /sign-in with success message
Request
GET /forgot-password
Request
POST /forgot-password
Name | Type | Description |
---|---|---|
email |
string |
Required User's email to send reset password request to. |
Response
Sends a password request email if it exists.
Redirect to /signin
Request
GET /reset-password
Name | Type | Description |
---|---|---|
code |
string |
Required A reset password code that was generated for one-time use and sent to the user via email. |
Request
POST /reset-password
Name | Type | Description |
---|---|---|
code |
string |
Required A reset password code that was generated for one-time use and sent to the user via email. |
newPassword |
string |
Required The new password for the user. Minimum 8 characters, maximum 50 characters. |
Response
Redirect to /signin
Request
Authentication Required
POST /subscriptions
Response
[
{
"planType": "all-monthly",
"receiptId": "GPA.3353-4716-1949-52255",
"expirationDate": "2018-03-10T07:14:06.065Z",
"expirationDateString": "March 10, 2018",
"expirationDateMs": 1520666046.065,
"cancellationDate": null,
"cancellationDateString": null,
"cancellationDateMs": null,
"userId": "a25b8f5640106f9e9a4990e592a3dc4e",
"receiptType": "android",
"inTrial": false,
"renewEnabled": true
}
]
Request
Authentication Required
POST /active-subscriptions
Response
[
{
"planType": "all-monthly",
"receiptId": "GPA.3353-4716-1949-52255",
"expirationDate": "2018-03-10T07:14:06.065Z",
"expirationDateString": "March 10, 2018",
"expirationDateMs": 1520666046.065,
"cancellationDate": null,
"cancellationDateString": null,
"cancellationDateMs": null,
"userId": "a25b8f5640106f9e9a4990e592a3dc4e",
"receiptType": "android",
"inTrial": false,
"renewEnabled": true
}
]
This is used by both browser and Mac/PC clients in a webview to create a new Pro subscription via Stripe. Creating subscriptions on iOS/Android clients don't use this because that's handled by iTunes and Google Play.
Request
Authentication Required
GET /new-subscription
Name | Type | Description |
---|---|---|
upgrade |
string |
Can be ios/android-monthly , ios/android-annual , or not specified. If user is upgrading from an ios or android only plan, redirect them to instructions on how to cancel their iOS/Android subscription after they complete this new subscription signup. No default value. |
browser |
boolean |
Shows top logo and navigation bar if true . Mac/PC clients using a webview should use false . Defaults to false . |
plan |
string |
The plan to subscribe to. Can be all-monthly or all-annual . Defaults to all-monthly . |
locale |
string |
Locale of user's machine, used for displaying expected currency to pay in, and recorded to Stripe as per legal requirements. User is not guaranteed to pay in this currency - actual payment currency will be based on the country of the credit card. Defaults to en-US . |
source |
string |
Used for Stripe's 3D Secure verification |
client_secret |
string |
Used for Stripe's 3D Secure verification |
Response
If user already has an active Pro subscription
Redirect to /account with "You already have a Pro subscription"
If user doesn't have an active Pro subscription
Render new subscription page using locale and existing payment methods, if any.
Request
Authentication Required
POST /new-subscription
Name | Type | Description |
---|---|---|
source |
string |
Required Source ID of a payment method either created by the frontend, or existing on the Stripe customer. |
is3ds |
boolean |
Whether or not the source is a newly created 3D Secure payment method. If it is, then a trial is not allowed. Also, we create a charge instead of invoice for the first month/year, then create a subscription plan with that duration as the "trial". Defaults to `false'. |
trial |
boolean |
Required Whether or not to request a trial period. If a user has already had a previous subscription, the server will return an error if another trial is requested. |
plan |
string |
Required The plan to subscribe to. Can be all-monthly or all-annual . |
upgrade |
string |
Can be ios/android-monthly , ios/android-annual , or not specified. If user is upgrading from an ios or android only plan, redirect them to instructions on how to cancel their iOS/Android subscription after they complete this new subscription signup. No default. |
browser |
boolean |
If true , success redirects to /clients . If false , success redirects to tunnels://stripesuccess . Defaults to false . |
Response
If upgrade
specified
Redirect to /account with message:
Be sure to cancel your iOS/Android-only subscription with Apple iTunes/Google Play
Else if browser
== true
Redirect to /clients
Else
Redirect to tunnels://stripesuccess
Request
Authentication Required
GET /cancel-subscription
Name | Type | Description |
---|---|---|
receiptId |
string |
Required Receipt ID of the subscription to cancel. |
receiptType |
string |
Required Receipt type of the subscription to cancel. Can be android , ios , or stripe . |
Response
If receiptType
== ios
/android
Redirect to /account with message:
Subscriptions made through the iOS/Android app must be cancelled through Apple/Google Play
Else
Render cancel-subscription view with receiptId
Request
Authentication Required
POST /cancel-subscription
Name | Type | Description |
---|---|---|
receiptId |
string |
Required Receipt ID of the Pro subscription to cancel. |
reason |
string |
The reason a user is cancelling their subscription. |
Response
Redirect to /account.
Request
GET /error-test
Request
GET /health
Response
Status 200
{
message: "OK from www." + DOMAIN
}
Request
GET /ip
Response
Status 200
{
ip: 12.34.56.78
}
Request
GET /download-speed-test
Response
Speed test files will be accessible by the following format, which allows for faster transfers:
https://<bucket>.s3-accelerate.amazonaws.com/<filename>
Status 200
{
bucket: confirmedvpn-speedtest-bucket
}
Responses with status code 500 will show Unknown Error
to user/client and will alert you by email at admin@[domain]
or team@[domain]
.
2XX - Success with Message
4XX - Client Error
429 - Too Many Requests
5XX - Server Error
JSON response with code
(see Error Codes
) and message
. 500 status code errors are server errors which aren't exposed to the client and show a code of -1.
{
code: 2,
message: "Some error message, like Password Too Short"
}
If a client calls an API too frequently, the server will respond with status code 429
and a JSON body of:
{
code: 999,
message: "Too many requests in this time frame.",
nextValidRequestDate: [Date of next valid request],
nextValidRequestDateHuman: [Human readable date of next valid request]
}
Status Code | Error Code | Message |
---|---|---|
500 | -1 | Internal server error |
200 | 1 | Email not confirmed |
200 | 6 | No active subscriptions |
200 | 62 | Renewer - Invalid purchase token |
200 | 995 | Renewer - Apple iTunes non-retryable error |
401 | 2 | Incorrect Login, Session Expired/Invalid, or No Such User |
400 | 3 | Request field validation error (e.g, Password too short, etc) |
400 | 5 | Missing receipt in receipt request |
400 | 9 | Invalid iOS IAP receipt |
400 | 10 | Error on response from Apple for receipt verification |
400 | 11 | Invalid IAP receipt type |
400 | 18 | No such confirmation code |
400 | 26 | Error getting subscription - no such subscription |
400 | 29 | Already had a trial, not allowing another |
400 | 31 | Error deleting user |
400 | 38 | Request Mac/Windows but no Pro subscription |
400 | 40 | Email already registered |
400 | 48 | Cannot convert shadow user that already has a confirmed email |
400 | 49 | Unrecognized product ID from iOS IAP receipt |
400 | 51 | Requested Android but no Android/Pro subscription |
400 | 52 | Requested iOS but no iOS/Pro subscription |
400 | 57 | Can't use iOS/Android test suite receipt outside of test suite |
400 | 59 | No such email |
400 | 60 | Email already confirmed |
400 | 63 | Android receipt does not match its signature |
400 | 64 | Android purchase failed on client side with Response code |
400 | 65 | Unable to decode Android base64 receipt sent from client |
400 | 66 | Missing field in android receipt |
400 | 67 | Android payment not received - still pending |
400 | 68 | Invalid android productId |
400 | 69 | OrderId in client receipt and Google verified receipt do not match |
400 | 77 | Error setting new user password: Invalid reset code |
400 | 81 | Can't delete default payment method |
400 | 82 | Can't delete last payment method |
400 | 89 | Wrong email or code for email opt-out |
400 | 99 | Admin - source ID already exists, choose new one |
400 | 108 | Error adding payment method card |
400 | 109 | Error setting default payment method card |
400 | 110 | Can't change email on a user that doesn't have a confirmed email |
400 | 125 | Referral code doesn't exist |
429 | 999 | Too many requests |
If you have any questions, concerns, or other feedback, please let us know any feedback in Github issues or by e-mail.
We also have a bug bounty program -- please email [email protected] for details.
This project is licensed under the GPL License - see the LICENSE.md file for details