Bring the power of pre-signed URLs to your apps. Signway is a gateway for redirecting authentic signed URLs to the requested API

Overview

Signway logo

Signway Book Signway Book coverage badge last release

A gateway that proxies signed requests to other APIs. Check the docs for more info. If you are looking for the managed version checkout this link https://www.signway.io.

Signway scheme

Sign your requests and proxy them

Terminal 1: Launch Signway Terminal 2: Create Signed URLs

Export the signing credentials for Signway:

export SW_ID="app-id"
export SW_SECRET="super-secure-string"

Export your OpenAI's API key here:

export API_KEY="your working token"

Launch Signway, ready for accepting requests signed with SW_ID and SW_SECRET:

docker run -p 3000:3000 gabotechs/signway \
$SW_ID \
$SW_SECRET \
--header "Authorization: Bearer $API_KEY"
  

Leave Signway running in this terminal...
















πŸ‘ˆ Export the same credentials:

export SW_ID="app-id"
export SW_SECRET="super-secure-string"

Install Signway's Python sdk:

python3 -m venv venv
source venv/bin/activate
pip install signway-sdk

Make a script for creating signed URLs:

cat << 'EOF' > sign.py
from signway_sdk import sign_url
import os

print(sign_url(
  os.environ['SW_ID'],
  os.environ['SW_SECRET'],
  "http://localhost:3000",
  "https://api.openai.com/v1/completions",
  10,  # <- URL expiration time in s
  "POST"
))
EOF

Make a request to the generated signed URL, as if it was OpenAI:

curl $(python sign.py) \
-H "Content-Type: application/json" \
-d '{
  "model": "text-davinci-003",
  "stream": true,
  "prompt": "Say this is a test"
}'

What does it solve?

Imagine that you have a setup that looks like this. Your backend accesses a public and authenticated api using an API token, and the response needs to be streamed in chunks, because it is a lot of data or because the response uses SSE.

sequenceDiagram
    participant frontend
    participant backend
    participant third_party api
    
    frontend->>+backend: request
    backend->>backend: authentication
    backend->>+third_party api: request + API token
    third_party api->>-backend: data stream
    backend->>-frontend: data stream

As you own the backend, you can safely configure there any api tokens needed for authenticating against the third party API, and re-stream back the data as it comes to the end user.

However, if you are using a serverless architecture, this gets tricky for two reasons:

  1. Most serverless setups, like AWS lamda with API Gateway, don't allow you to stream the response, you can only send back one final blob.
  2. Your serverless function would need to live for a very long time, even if it is just doing slow IO data transfer, so cost may increase significantly.

This is where Signway enters the game. Signway provides you a way of letting the end user do the request "almost directly" to the third party API in a secure way without the need of leaking credentials.

The schema using Signway looks like this:

sequenceDiagram
    participant frontend
    participant serverless backend
    participant Signway
    participant third_party api

    frontend->>+serverless backend: request
    serverless backend->>serverless backend: authentication
    serverless backend->>serverless backend: create signed url using an "id" and a "secret"
    serverless backend->>-frontend: signed URL
    frontend->>+Signway: signed URL + request
    Signway->>Signway: verify signature for "id" using "secret"
    Signway->>+third_party api: request + API token
    third_party api->>-Signway: data stream
    Signway->>-frontend: data stream
    

This way you leverage heavy IO work to Signway, which is a high performant gateway server written in Rust prepared for heavy throughput, and you are able to stream data to end users from APIs that send you data chunk by chunk.

Signing algorithm

The signing algorithm is inspired strongly by AWS signature v4, the same that s3 uses for generating pre-signed URLs for letting clients interact with buckets directly.

Generating a signed URL requires that the signer (usually an application's backend) knows a public id and a private secret. The id will live in plain text in the signed URL, and the secret will be used for creating the request's signature, but it is not included in the URL.

Signway, who knows which secret is associated to which id, will take the request and recalculate its signature. If the declared signature and the calculated one match, and the request has not expired, it will redirect the request to the specified third party API, adding any preconfigured headers for that id, like API tokens.

Usage

The server is meant to be used with docker, there are public images with support for linux/arm64 and linux/amd64.

docker run gabotechs/signway my-id my-secret

You can also declare the headers that will be automatically added to the proxy-ed request in case of an authentic signed request is received:

docker run gabotechs/signway my-id my-secret -h 'Authorization:Bearer my-secret-token'

Pre-signed URL generation

Typically, the Signway server will be publicly accessible to the internet, prepared to accept requests with a pre-signed URL, but someone needs to create those pre-signed URLs. This should be a trusted source, as it needs to know the signing secret, like an application's backend.

There is support for generating Signway pre-signed URLs for the following languages:

In order to generate a pre-signed URL, knowing the id and the secret that Signway is expecting is necessary, and as the secret is private, it is important to be careful not to leak it.

You might also like...
A simple tool in Rust to split urls in their protocol, host, port, path and query parts.

rexturl A simple tool to split urls in their protocol, host, port, path and query parts. Install cargo install rexturl or clone the source code and r

Modrinth API is a simple library for using Modrinth's API in Rust projects

Ferinth is a simple library for using the Modrinth API in Rust projects. It uses reqwest as its HTTP(S) client and deserialises responses to typed structs using serde.

The Safe Network Core. API message definitions, routing and nodes, client core api.

safe_network The Safe Network Core. API message definitions, routing and nodes, client core api. License This Safe Network repository is licensed unde

Proxy copilot api to openai's gpt-4 api

Proxying Copilot API to OpenAI's GPT-4 API Usage Start the Server export GHU_TOKEN=ghu_xxxx; ./copilot2chat Or sh start.sh start # start the server th

Obtain (wildcard) certificates from let's encrypt using dns-01 without the need for API access to your DNS provider.

Agnos Presentation Agnos is a single-binary program allowing you to easily obtain certificates (including wildcards) from Let's Encrypt using DNS-01 c

πŸ”Œ A curseforge proxy server, keeping your API key safe and sound.

πŸ”Œ CFPROXY - The curseforge proxy server Curseforge has locked down their API and now restricts access without authentification. This spells trouble f

Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password.

nostr-irc Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password. Experimental code, use

Docker daemon API in Rust

Bollard: an asynchronous rust client library for the docker API Bollard leverages the latest Hyper and Tokio improvements for an asynchronous API cont

A pure Rust implementation of WebRTC API
A pure Rust implementation of WebRTC API

A pure Rust implementation of WebRTC API

Releases(v0.4.1)
Owner
Gabriel
Passionate developer and new technology lover aiming to make the world a better place with software πŸ’ͺ
Gabriel
A library-first, lightweight, high-performance, cloud-native supported API gatewayπŸͺ by RUST

Preview version, will not guarantee the stability of the API! Do NOT use in production environment! A library-first, lightweight, high-performance, cl

Ideal World 4 May 7, 2023
A sample API Gateway built in Rust (work in progress) for learning purposes

rust-api-gateway A sample API Gateway built in Rust (work in progress) for learning purposes. You can follow along by reading the tutorial articles: P

Luis Soares 4 Oct 29, 2023
A Prometheus Aggregation Gateway for FAAS applications

Gravel Gateway Gravel Gateway is a Prometheus Push Gateway for FAAS applications. In particular it allows aggregation to be controlled by the incoming

Colin Douch 85 Nov 23, 2022
Drop-in proxy for Discord gateway connections and sessions allowing for zero downtime deploys

gateway-proxy This is a very hacky project, so it might stop working if Discord changes their API core. This is unlikely, but keep that in mind while

Jens Reidel 39 Nov 26, 2022
A Prometheus Aggregation Gateway for FAAS applications

Gravel Gateway Gravel Gateway is a Prometheus Push Gateway for FAAS applications. In particular it allows aggregation to be controlled by the incoming

Colin Douch 85 Nov 23, 2022
A rust-based command line tool to serve as a gateway for a Internet Computer replica.

icx-proxy A command line tool to serve as a gateway for a Internet Computer replica. Contributing Please follow the guidelines in the CONTRIBUTING.md

DFINITY 25 Sep 6, 2022
The registration server for WebThings Gateway.

Registration Server This server exposes an HTTP API that lets you register a WebThings Gateway for tunneling support. When combined with a PowerDNS se

WebThings 78 Nov 21, 2022
WireGuard gateway with SNI for portable connectivity.

Gateway This is a daemon that controls gateway servers. Gateway servers are servers that fulfil three major purposes: facilitating connectivity betwee

Fractal Networks 5 Aug 9, 2022
User-space Wireguard gateway allowing sharing network connection from environment where usual routing rules are inaccessible.

wgslirpy A command line tool (and a Rust library) for accepting incoming connections within a Wireguard link and routing them to external network usin

Vitaly Shukela 4 Aug 21, 2023
Rust crate for scraping URLs from HTML pages

url-scraper Rust crate for scraping URLs from HTML pages. Example extern crate url_scraper; use url_scraper::UrlScraper; fn main() { let director

Pop!_OS 35 Aug 18, 2022