Coder Social home page Coder Social logo

http-auth-middleware's Introduction

http-auth-middleware

This repo is an example of how to compose a middleware component with a business logic component.

Repo structure

The github-oauth/ directory contains an API for using GitHub oauth in an application. It consists of

  1. The authorize handler which kicks off the github oauth flow allowing a user to give permissions to a GitHub app
  2. The callback handler which GitHub uses as the redirect url in the oauth flow. The callback handler is responsible for taking a code from the URL param and exchanging it for authentication token from GitHub for the user.
  3. The authenticate handler which validates a given access token in an incoming request with the GitHub user API.
  4. The login handler which returns a login button.

The example/ directory contains a Spin application which consists of one http handler which returns an HTTP response contains Hello, Fermyon! in the body. In the spin.toml file, the component build instructions point to a build.sh script which builds the example component and composes it with the github-oauth component.

Demo instructions

Pre-requisites

cargo install --git https://github.com/bytecodealliance/cargo-component --tag v0.4.0 cargo-component --locked
cargo install --git https://github.com/bytecodealliance/wasm-tools wasm-tools --locked
  • Install latest Spin

  • Create an OAuth App in your GitHub Developer Settings. Set the callback URL to http://127.0.0.1:3000/login/callback. Accept defaults and input dummy values for the rest of the fields.

    • Save the Client ID
    • Generate a new Client Secret and save that as well

Build the components and run the demo

# Build the middleware
cargo component build --manifest-path github-oauth/Cargo.toml --release

# Build and run the example
spin up --build -f example -e CLIENT_ID=<YOUR_GITHUB_APP_CLIENT_ID> -e CLIENT_SECRET=<YOUR_GITHUB_APP_CLIENT_SECRET>

# Open http://127.0.0.1:3000/login in a browser

Running with Wasmtime

This component can be universally run by runtimes that support WASI preview 2's HTTP proxy world. For example, it can be served directly by Wasmtime, the runtime embedded in Spin. First, ensure you have installed the Wasmtime CLI with at least version v14.0.3. We will use the wasmtime serve subcommand which serves requests to/from a WASI HTTP component.

Unfortunately, wasmtime serve does not currently support setting environment variables in component, so we cannot pass environment variables at runtime as we did with Spin. Instead, set the CLIENT_ID and CLIENT_SECRET oauth app secrets generated in the prerequisites step as environment variables and build the oauth component with the compile-time-secrets feature flag. The flag ensures the environment variables are set in the component at compile time so they are no longer needed from the WebAssembly runtime. It is not recommended to embed secrets in production applications; rather, environment variables should be passed at runtime if the WebAssembly Host supports it. This is configurable with Spin and Fermyon Cloud.

export CLIENT_ID=<YOUR_GITHUB_APP_CLIENT_ID> 
export CLIENT_SECRET=<YOUR_GITHUB_APP_CLIENT_SECRET>
cargo component build --manifest-path github-oauth/Cargo.toml --release --features compile-time-secrets
# Compose the auth component with the business logic component using wasm-tools
cd example && ./build.sh
# Serve the component on the expected host and port
wasmtime serve service.wasm --addr 127.0.0.1:3000

Configuring the callback URL

Instead of using the default callback URL of http://127.0.0.1:3000/login/callback, you can configure the URL in an environment variable that is resolved at build time. This is useful in the case that the component is not running locally, rather in a hosted environment such as Fermyon Cloud.

export AUTH_CALLBACK_URL=http://my-auth-app.fermyon.app/login/callback
export CLIENT_ID=<YOUR_GITHUB_APP_CLIENT_ID> 
export CLIENT_SECRET=<YOUR_GITHUB_APP_CLIENT_SECRET>
cargo component build --manifest-path github-oauth/Cargo.toml --release --features compile-time-secrets
spin deploy -f example 

Using Runtime Environment Variables

Not all WebAssembly runtimes fully support exporting the wasi:cli/environment interface to components. Spin, however, does support this and can load environment variables into a component's environment. Simply pass the environment variables during a spin up:

cargo component build --manifest-path github-oauth/Cargo.toml --release
spin up --build -f example -e CLIENT_ID=<YOUR_GITHUB_APP_CLIENT_ID> -e CLIENT_SECRET=<YOUR_GITHUB_APP_CLIENT_SECRET>

To deploy an app to Fermyon Cloud that uses environment variables, you need to configure them in your spin.toml. Update the example application manifest to contain your CLIENT_ID and CLIENT_SECRET environment variables. Since we do not know the endpoint for our Fermyon Cloud application until after the first deploy, we cannot yet configure the AUTH_CALLBACK_URL.

[component.example]
source = "service.wasm"
allowed_outbound_hosts = ["https://github.com", "https://api.github.com"]
environment = { CLIENT_ID = "YOUR_GITHUB_APP_CLIENT_ID", CLIENT_SECRET = "YOUR_GITHUB_APP_CLIENT_SECRET" }
[component.example.build]
command = "./build.sh"

Now deploy your application.

$ spin deploy -f example
Uploading example version 0.1.0 to Fermyon Cloud...
Deploying...
Waiting for application to become ready............. ready
Available Routes:
  example: https://example-12345.fermyon.app (wildcard)

In the example deploy output above, the app now exists at endpoint https://example-12345.fermyon.app. This means our callback URL should be https://example-12345.fermyon.app/login/callback. Configure this in the spin.toml with another environment variable:

[component.example]
source = "service.wasm"
allowed_outbound_hosts = ["https://github.com", "https://api.github.com"]
environment = { CLIENT_ID = "YOUR_GITHUB_APP_CLIENT_ID", CLIENT_SECRET = "YOUR_GITHUB_APP_CLIENT_SECRET", AUTH_CALLBACK_URL = "https://example-<HASH>.fermyon.app/login/callback" }
[component.example.build]
command = "./build.sh"

Now, redeploy with another spin deploy -f example. Be sure to update your GitHub OAuth App to update the callback URL.

This example uses environment variable to import secrets, since that is a ubiquitous interface and enables cross cloud portability of your component. If you are interested in configuring dynamic secrets that are not exposed in text in your spin.toml and can be updated with the spin cloud variables CLI, see Spin's documentation on configuring application variables.

http-auth-middleware's People

Contributors

fibonacci1729 avatar kate-goldenring avatar michellen avatar thangchung avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http-auth-middleware's Issues

add CI

  • at minimum, make sure components compile

The example is broken

At the step of spin build, I have hit an error

error: failed to connect instance `$input` to definition component `/Users/mossaka/Developer/mossaka/http-auth-middleware-go/example/target/wasm32-wasi/release/example.wasm`

Caused by:
    0: source instance export `wasi:http/[email protected]` is not compatible with target instance import `wasi:http/[email protected]`

I think this is due to some WASI HTTP spec change upstream. I also tried to pin the spin version to v2.0.1 but it still doesn't work.

[Question]: Is it a middleware?

Hi,

thanks for this great example.

I have one question though: Is it a "real" middleware? From my understanding a middleware can intercept requests and responses, but to me, it looks like this example only shows how to intercept the request.
Is it possible to also get a handle on the response or would this need another component after the example component?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.