WrapFast includes a simple Node.js backend to make requests to OpenAI’s and Anthropic’s API.
The purpose of this is prevent storing the API keys within the mobile app and making the requests from there. It’s a pretty bad practice because anyone can easily sniff your HTTP requests and extract the key, for example using the utility proxy Charles.
To avoid this, and save thousand of dollars for you being hacked, WrapFast hides the HTTP request behind a custom backend.
<aside> 💡 If you do not want to deploy a backend, as another option WrapFast supports AI Proxy to make requests securely to OpenAI without exposing your API key. You will find implementations of ChatGPT, Vision and DALL-E in each service class.
Feel free to create an account and check their documentation here: aiproxy.pro Integration Guide: https://www.aiproxy.pro/docs/integration-guide.html Docs: https://github.com/lzell/AIProxySwift?tab=readme-ov-file#how-to-update-the-package
</aside>
The backend implements 4 endpoints that are called from the iOS boilerplate:
/auth
GET Endpoint to authenticate and obtain a secret key/chatgpt
POST Endpoint to make requests to ChatGPT API/vision
POST Endpoint to make requests to Vision API/dalle
POST Endpoint to make requests to DALL·E API/anthropic-messages
POST Endpoint to make requests to Anthropic APILet's take a closer look at them later, but first let's learn how to set up and deploy our backend.
First of all you need to have installed Node.js and NPM in your Mac.
The minimum required Node version is 21.2.0
To install it just open a Terminal and paste this commands:
brew install node
<aside> ⚠️ If you don’t have Homebrew installed, paste this on your Terminal: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
</aside>
Type node -v
to check that Node is correctly installed.
You can find the variables that the WrapFast backend uses in the .env.example
file.
Remove the trailing .example
and open it and replace the values with the proper ones:
<aside>
⚠️ Take into account that the .env
file is ignored by Git, because it is included in the .gitgnore
file.
</aside>
API_KEY
Your OpenAI’s API key. You can find it in your OpenAI Dashboard, within API Keys section.ANTHROPIC_API_KEY
Your Anthropic’s API key. You can find it in your Anthropic Console, within API Keys section.AUTH_SECRET_KEY
and HMAC_SECRET_KEY
Secret keys to authenticate your iOS app against the backend. You have to generate them executing the script secret_generator.js
in a Terminal:node secret_generator.js
It generates a new secret key every time you execute it. Generate two and paste it in AUTH_SECRET_KEY
and HMAC_SECRET_KEY
You will learn below how the Authentication Flow works. For now just replace the variables 🙂
AUTH_LIMIT
Number of requests per user, per 5 minutes allowed to authentication endpoint. These limits are for preventing abuse to your backend. Tweak it if you need it.PROMPT_LIMIT
Number of requests per user, per 5 minutes allowed to OpenAI endpoints. These limits are for preventing abuse to your backend. Tweak it if you need it.VISION_MAX_TOKENS
Maximum tokens of Vision text response to prevent excessive costs. Tweak it regarding your needs. The more tokens used, the more API cost.ANTHROPIC_MAX_TOKENS
Maximum tokens of Messages text response to prevent excessive costs. Tweak it regarding your needs. The more tokens used, the more API cost.NODE_VERSION
This is not necessary for deploying in a local environment. This is necessary to tell a hosting service (like [Render.com](http://Render.comhttps://render.com)) which version should it use to deploy your web service. Check the proper section below to learn how to deploy with a hosting service.TELEGRAM_BOT_KEY
and TELEGRAM_CHANNEL_ID
These are completely optional. Use them if you want to send messages to your Telegram Bot.HMAC is a way to make sure messages sent between two places online stay secret and unchanged.
It's like sealing a letter in an envelope with a special wax seal, where the seal is made using a secret recipe.
Only the sender and the receiver know the recipe, so if the seal is intact when the receiver gets the letter, they can be sure it hasn't been opened or changed along the way.
In the WrapFast backend, we use HMAC to add this kind of security to messages or data we send and receive in our apps.
We use two keys that you have to generate with this included script secret_generator.js
Open a Terminal and type to generate a secret key:
node secret_generator.js
Set the two keys generated as AUTH_SECRET_KEY
and HMAC_SECRET_KEY
You have to set the AUTH_SECRET_KEY
also in the Xcode Project, within Constant.swift
file:
enum Api {
// Auth key generated with the script 'secret_generator.js'
// It also needs to be configured in the backend side
static let authKey = "YOUR_GENERATED_AUTH_KEY"
}
In order to authenticate to the backend from the WrapFast iOS app:
GET
request to /auth
endpoint. We pass a X-Signature header, containing the path of the request, hashed with the authKey. You can find this in the Xcode Project at Endpoints.swift
:"X-Signature": "\\(CryptoUtils.shared.createHmac(key: Const.Api.authKey, phrase: "/" + path))"
HMAC_SECRET_KEY
that we safely store it in the device’s Keychain.chatgpt
, vision
, and dalle
including a X-Signature header in the same way we did with auth
endpoint:var header: [String : String]? {
switch self {
case .auth:
return [
"X-Signature": "\\(CryptoUtils.shared.createHmac(key: Const.Api.authKey, phrase: "/" + path))"
]
// To make requests to our backend endpoints, we fetch the auth secret key stored in the keychain and send it
// within a X-Signature header.
// We also send our app identifier to allow handle custom login within the backend depending on which app
// make the request.
case .vision, .chatgpt, .dalle:
let keychain = KeychainSwift()
let signature = CryptoUtils.shared.createHmac(key: keychain.get(Const.Keychain.tokenKey) ?? "", phrase: "/" + path)
return [
"X-Signature": "\\(signature)",
"X-App-Identifier": "\\(Const.Api.appIdentifier)"
]
}
}
<aside>
⚠️ In order to be able to make requests to GPT endpoints, you need to have fetched the HMAC_SECRET_KEY
from /auth
endpoint at least once from your app, and store it securely in the Keychain.
For instance, in the WrapFast boilerplate we do it within the init()
of VisionVM, which is the first View that appears once the user has signed in:
**await** fetchBackendAuthIfNecessary()
</aside>
Once you have the Environment Variables properly set, you can deploy the backend locally in your Mac. Thus, you can develop your app and use the backend in debug. To do so:
cd wrapfast-backend
npm install
node wrapfast_backend.js
Your server will start running on http://localhost:10000/
Run WrapFast iOS app in a Simulator and try the built-in integration with DALL·E, Vision and ChatGPT
The server’s URL that the iOS app uses is set in the Constants.swif
file, in the Api.baseURL
parameter.
<aside>
⚠️ It is important that the URL you set as baseURL
ends with a Slash /
</aside>
In DEBUG
it is set to local host and in production you should set your production URL.
<aside>
💡 If you want to use the local backend with a real device instead of the Simulator, use as baseURL
the proper local IP. For instance: http://192.168.1.44:10000/
To know what’s your IP type in a Terminal: ipconfig getifaddr en0
</aside>
You will learn in the next section how to deploy your backend in a hosting service.
When your app is live in the App Store or TestFlight, you may need to publish your backend to allow be accessed publicly by your apps.
As indie developers, the most common approach is using a service to host it like Render, Heroku, Netlify, etc.—if you don’t have your own infrastructure.
In this section we are going to explain how to deploy your web service using Render.
Render offers a quite generous free tier to host web services for free. It is very suitable for light MVPs that doesn’t require too much work load, as our case is.
<aside> ⚠️ Take into account that the free instances will spin down after 10 minutes of inactivity, which can delay new requests by 50 seconds or more. To offer a better experience to your users I recommend upgrading to the first paid tier which is just $5 monthly.
</aside>
To deploy your backend you need to push the backend to a GitHub or GitLab repository. Render will detect every new commit you push, deploying new changes automatically.
Once you have the backend in GitHub or Gitlab, follow these steps:
Create a Render account.
Click New > Web Service
Select deploy from a respository
You may be redirect to GitHub to allow Render access your repository:
Connect your repository:
Fill the field like in this screenshot (the name is up to you):
Scroll down and find the Environment Variables section. Your can type them manually but the most convenient way is add them pasting from your .env
file.
Click on Create Web Service and it will start deploying…
Ignore the warnings, when you see Your service is live 🎉 in the logs, your backend is ready to be accessible from your apps.