Giter Club home page Giter Club logo

siwe-oidc's Introduction

OpenID Connect Identity Provider for Sign-In with Ethereum

Getting Started

Two versions are available, a stand-alone binary (using Axum and Redis) and a Cloudflare Worker. They use the same code base and are selected at compile time (compiling for wasm32 will make the Worker version).

The front-end depends on WalletConnect, meaning you will need to create a project with them and have the environment variable PROJECT_ID set when you build the front-end.

Cloudflare Worker

You will need wrangler.

First, copy the configuration file template:

cp wrangler_example.toml wrangler.toml

Then replace the following fields:

  • account_id: your Cloudflare account ID;
  • zone_id: (Optional) DNS zone ID;
  • kv_namespaces: a KV namespace ID (created with wrangler kv:namespace create SIWE_OIDC); and
  • the environment variables under vars.

You will also need to add a secret RSA key in PEM format:

wrangler secret put RSA_PEM

At this point, you should be able to create/publish the worker:

wrangler publish

The IdP currently only supports having the frontend under the same subdomain as the API. Here is the configuration for Cloudflare Pages:

  • Build command: cd js/ui && npm install && npm run build;
  • Build output directory: /static; and
  • Root directory: /. And you will need to add some rules to do the routing between the Page and the Worker. Here are the rules for the Worker (the Page being used as the fallback on the subdomain):
siweoidc.example.com/s*
siweoidc.example.com/u*
siweoidc.example.com/r*
siweoidc.example.com/a*
siweoidc.example.com/t*
siweoidc.example.com/j*
siweoidc.example.com/c*
siweoidc.example.com/.w*

Stand-Alone Binary

**WARNING - ** Due to the reliance on WalletConnect, and the project ID being loaded at compile-time, the current version of the Docker image won't have a working web app.

Dependencies

Redis, or a Redis compatible database (e.g. MemoryDB in AWS), is required.

Starting the IdP

The Docker image is available at ghcr.io/spruceid/siwe_oidc:0.1.0. Here is an example usage:

docker run -p 8000:8000 -e SIWEOIDC_REDIS_URL="redis://redis" ghcr.io/spruceid/siwe_oidc:latest

It can be configured either with the siwe-oidc.toml configuration file, or through environment variables:

  • SIWEOIDC_ADDRESS is the IP address to bind to.
  • SIWEOIDC_REDIS_URL is the URL to the Redis instance.
  • SIWEOIDC_BASE_URL is the URL you want to advertise in the OIDC configuration (e.g. https://oidc.example.com).
  • SIWEOIDC_RSA_PEM is the signing key, in PEM format. One will be generated if none is provided.

OIDC Functionalities

The current flow is very basic -- after the user is authenticated you will receive:

  • an Ethereum address as the subject (sub field); and
  • an ENS domain as the preferred_username (with a fallback to the address).

For the core OIDC information, it is available under /.well-known/openid-configuration.

OIDC Conformance Suite:

  • 🟨 (25/29, and 10 skipped) basic (email scope skipped, profile scope partially supported, ACR, prompt=none and request URIs yet to be supported);
  • 🟩 config;
  • 🟧 dynamic code.

TODO Items

  • Additional information, from native projects (e.g. ENS domains profile pictures), to more traditional ones (e.g. email).

Development

Cloudflare Worker

wrangler dev

You can now use http://127.0.0.1:8787/.well-known/openid-configuration.

At the moment it's not possible to use it end-to-end with the frontend as they need to share the same host (i.e. port), unless using a local load-balancer.

Stand Alone Binary

A Docker Compose is available to test the IdP locally with Keycloak.

  1. You will first need to run:
docker-compose -f test/docker-compose.yml up -d
  1. And then edit your /etc/hosts to have siwe-oidc point to 127.0.0.1. This is so both your browser, and Keycloak, can access the IdP.

  2. In Keycloak, you will need to create a new IdP. You can use http://siwe-oidc:8000/.well-known/openid-configuration to fill the settings automatically. As for the client ID/secret, you can use sdf/sdf.

Disclaimer

Our identity provider for Sign-In with Ethereum has not yet undergone a formal security audit. We welcome continued feedback on the usability, architecture, and security of this implementation.

siwe-oidc's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  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  avatar

siwe-oidc's Issues

Siwe doesn't work on mobile

Have been trying to sign in with wallet to oidc.signinwithethereum.org via mobile phone, with Rainbow and metamask, and it doesn't work:

  1. I click sign in with Ethereum
  2. It redirects me to metamask, where I click connect
  3. When I go back to the app, nothing happens.

network does not support ENS

If a user tries to Sign-In-With-Ethereum using the public OIDC with a non-supported ENS network, a console error appears stating: network does not support ENS (so far only Ethereum Mainnet and Goerli supports it. Polygon, Arbitrum and Avalanche have throw me the same error).

The problem is that when a normal user tries to sign in with a different network, there is no error message indicating him that he should change network or use a ENS-supported network. I think there could be two solutions:

  1. In our application (and I assume most applications) we don't need to know the wallet network, we only need to have a valid signature to login in our users. We could send a query param on the siginwithethereum.org link with useENS = true || false so users can sign in without worrying about the currently set network.

  2. Add an error handler in the Client Web3 Modal to indicate the user that the current selected network does not support ENS.

image

ID token expiry duration

I notice the default expiry duration for id token is just 60 seconds.

This seems rather short and inconvenient. In comparison, Auth0 has an 8 hour default duration .

Do we have plan to make it configurable? Or, would it be best to change the default duration to at least 2~3 hours?

How to backup clients

I managed to deploy SIWE OIDC in my cloud environment as docker containers but now I'm facing the problem that every time such containers restart I lose the registered clients. How can I manage persistence and backup?

To be precise the system requires the client id and secret got from the oidc registration_endpoint. This configuration is placed in our IAM system to enable our signin/signup flows.

Is this doable by providing a docker volume?

chainId is hardcoded in sub claim

I'm using the auth0 siwe social connection; the sub claim contains address with what I'm assuming is the chainId e.g. "eip155:1:0x976EA74026E726554dB657fA54763abd0C3a0aa9"

Is my assumption is correct? i.e. that the 1 between eip155 and address is the chainId? If so, can we update the code to remove the hardcoded 1 and use the chainId sent with the siwe message?

Perform forward resolution after reverse resolution

ethers-rs does not check forward resolution result against a reverse resolution record. According to the ENS docs, we would need to do that. We should make sure the forward resolution matches the reverse resolution record.

From the ENS docs (docs.ens.domains/dapp-developer-guide/resolving-names):

ENS does not enforce the accuracy of reverse records - for instance, anyone may claim that the name for their address is 'alice.eth'. To be certain that the claim is accurate, you must always perform a forward resolution for the returned name and check it matches the original address.

Limit OIDC Client Registration to Specific IPs/Domains (feature request?)

I've successfully set up an OIDC provider docker image to work with my Matrix Synapse home server. There's just one opening for abuse that I can think of which is that anyone else, not sure why they would, could request registration credentials for their own client(s) and there doesn't seem to be a way to limit this. That I'm aware of anyway.

By default the SIWEOIDC_ADDRESS is set to "0.0.0.0". Attempting to change this to oicd-client-domain or its public IP address obviously breaks the sign in process from any other device.

Is there another setting or environment variable that exists but not documented capable of limiting which clients can register?

Add option to select and consent to ENS name

Currently, after ENS reverse resolution and if an ENS name was found, the name will be propagated as the preferred_username in the id_token.

The user should have the option to see and give consent to which ENS name will be propagated to the OIDC client.

If multiple ENS names were registered, the user should select which ENS name should be used. The user can also decide that no ENS name will be propagated to the OIDC client.

The following scenarios should be supported:

  1. user has no ENS name -> no extra steps needed
  2. user has 1 ENS name -> user sees which ENS name was resolved and has the option to unselect the ENS name to be included in the response.
  3. user has multiple ENS names -> same as above but may decide which ENS name should be propagated.

The Docker Compose instance doesn't allow remote access to KeyCloak

I'm running the Dockerized stacks from a cloud. As such, I can only do remote access. While doing it, I got HTTP 403 forbidden. It would be great if remote access to KeyCloak works out of the box.

My workaround is to setup KeyCloak Docker instance via SSH from the CLI instead.

/opt/keycloak/bin/kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin --password yourpassword
/opt/keycloak/bin/kcadm.sh create clients -r master -s clientId=myclientid -s 'redirectUris=["*"]' -i -s clientAuthenticatorType=client-secret -s secret=myclientsecret
/opt/keycloak/bin/kcadm.sh create identity-provider/instances --server http://localhost:8080 -r master --user admin --password yourpassword -s alias=oidc -s providerId=oidc -s enabled=true -s 'config.useJwksUrl="true"' -s config.authorizationUrl=https://spruce.mydomain.org/authorize -s config.tokenUrl=https://spruce.mydomain.org/token -s config.clientId=myclientid -s config.clientSecret=myclientsecret

Support using Ory Hydra instead of KeyCloak

I have found that KeyCloak is overkill for small servers. It takes a while to be live, after a docker compose up. While looking for a more performant alternative to KeyCloak, I found Ory Hydra. However, I wasn't able to wire SIWE to it. I'm not sure if I need to configure SIWE instead of Ory Kratos instead. Help appreciated!

Cannot build demo example

When following the steps in example/demo to start the demo, I get this error. I get the same error when running cargo build directly.

chris@macbook demo % trunk serve --open
2023-06-01T18:11:20.649653Z  INFO 📦 starting build
2023-06-01T18:11:20.650188Z  INFO spawning asset pipelines
2023-06-01T18:11:25.143783Z ERROR ❌ error
error from HTML pipeline

Caused by:
    0: error getting cargo metadata
    1: `cargo metadata` exited with an error:     Updating crates.io index
           Updating git repository `https://github.com/sbihel/openidconnect-rs`
       error: failed to select a version for `openidconnect`.
           ... required by package `demo v0.1.0 (/Users/chris13524/git/github.com/spruceid/siwe-oidc/example/demo)`
       versions that meet the requirements `*` are: 3.0.0-alpha.1
       
       the package `demo` depends on `openidconnect`, with features: `rustcrypto` but `openidconnect` does not have these features.
       
       
       failed to select a version for `openidconnect` which could resolve this conflict
2023-06-01T18:11:25.144359Z  INFO 📡 serving static assets at -> /
2023-06-01T18:11:25.144493Z  INFO 📡 server listening at http://127.0.0.1:8080

If I remove the rustcrypto feature from Cargo.toml openidconnect dependency, then it seems to build without error. However, the page is blank and I get these messages in the console:

localhost/:1 Uncaught TypeError: Failed to resolve module specifier "env". Relative references must start with either "/", "./", or "../".
localhost/:1 The resource http://localhost:8080/demo-ac8912ababa70052_bg.wasm was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it has an appropriate `as` value and it is preloaded intentionally.

Latest Wrangler version issue, when trying to deploy to cloudflare

I am trying to deploy my own OIDC provider to cloudflare and get stuck during the wrangler publish step. I followed every step of this deployment guide:
https://docs.login.xyz/servers/oidc-provider/deployment-guide

this is the error i get :
..........................................
Compiling bincode v1.3.3
Compiling urlencoding v2.1.2
Compiling ethers-providers v1.0.2
Compiling worker v0.0.12
Compiling siwe-oidc v0.1.0 (/Users/samuelandert/Documents/Development/oidc.homin.io)
Finished release [optimized] target(s) in 29.16s
[INFO]: ⬇️ Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with wasm-opt...
[INFO]: ✨ Done in 31.65s
[INFO]: 📦 Your wasm pkg is ready to publish at
**
✘ [ERROR] Could not resolve "./index_bg.wasm"

index_bg.js:2:22:
  2 │ import * as wasm from './index_bg.wasm';
    ╵                       ~~~~~

1 error
Error: esbuild exited with status exit status: 1

✘ [ERROR] Running custom build cargo install -q worker-build && worker-build --release failed. There are likely more logs from your build command above.
is there any other .env config I am missing?

--- 2024-04-29T08:52:26.648Z debug
🪵 Writing logs to "/Users/samuelandert/.wrangler/logs/wrangler-2024-04-29_08-52-26_569.log"

--- 2024-04-29T08:52:26.648Z debug
Failed to load .env file ".env": Error: ENOENT: no such file or directory, open '.env'
at Object.openSync (node:fs:581:18)
at Object.readFileSync (node:fs:457:35)
at tryLoadDotEnv (/Users/samuelandert/.nvm/versions/node/v21.0.0/lib/node_modules/wrangler/wrangler-dist/cli.js:124915:72)
at loadDotEnv (/Users/samuelandert/.nvm/versions/node/v21.0.0/lib/node_modules/wrangler/wrangler-dist/cli.js:124924:12)
at /Users/samuelandert/.nvm/versions/node/v21.0.0/lib/node_modules/wrangler/wrangler-dist/cli.js:167363:20
at /Users/samuelandert/.nvm/versions/node/v21.0.0/lib/node_modules/wrangler/wrangler-dist/cli.js:132342:16
at maybeAsyncResult (/Users/samuelandert/.nvm/versions/node/v21.0.0/lib/node_modules/wrangler/wrangler-dist/cli.js:130563:44)
at /Users/samuelandert/.nvm/versions/node/v21.0.0/lib/node_modules/wrangler/wrangler-dist/cli.js:132341:14
at /Users/samuelandert/.nvm/versions/node/v21.0.0/lib/node_modules/wrangler/wrangler-dist/cli.js:130550:22
at Array.reduce () {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '.env'
}

--- 2024-04-29T08:52:26.693Z warn
�[33m▲ �[43;33m[�[43;30mWARNING�[43;33m]�[0m �[1mwrangler publish is deprecated and will be removed in the next major version.�[0m

Please use wrangler deploy instead, which accepts exactly the same arguments.


--- 2024-04-29T08:52:26.697Z warn
�[33m▲ �[43;33m[�[43;30mWARNING�[43;33m]�[0m �[1mProcessing wrangler.toml configuration:�[0m

�[1m😶 Ignored�[0m: "type":
Most common features now work out of the box with wrangler, including modules, jsx,
typescript, etc. If you need anything more, use a custom build.
�[1mDeprecation�[0m: "build.upload.format":
The format is inferred automatically from the code.
�[1mDeprecation�[0m: "build.upload.main":
Delete the build.upload.main and build.upload.dir fields.
Then add the top level main field to your configuration file:
main = "build/worker/shim.mjs"
�[1mDeprecation�[0m: "build.upload.dir":
Use the top level "main" field or a command-line argument to specify the entry-point for the
Worker.
Deprecation: The build.upload.rules config field is no longer used, the rules should be
specified via the rules config field. Delete the build.upload field from the configuration
file, and add this:
[[rules]]
globs = [ "**/*.wasm" ]
type = "CompiledWasm"


--- 2024-04-29T08:52:26.697Z log
Running custom build: cargo install -q worker-build && worker-build --release

The sample docker-compose.yml requires user to add siwe-oidc entry in their /etc/hosts

Is there a way to not having to manually edit /etc/hosts in

# Need siwe-oidc in /etc/hosts for localhost to allow both the host and Keycloak to reach the IdP
? I often do docker compose down, which resets the IP address. Having to edit this manually every time slows down my debug workflow. Also, I am on NixOS, so /etc/hosts is a symlink to a /nix/store and is editable only by nixos-rebuild or similar commands

I have tried various options, such as

  1. Specifying 127.0.0.1 as the address. This failed with "couldn't connect to server"
  2. Specifying 127.0.0.1 as the address, with network_mode: "host". This failed with siwe-oidc not being able to access the Redis container.
  3. Automatically fetch the container IP address via sudo docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$siwe_container_name" and change SIWEOIDC_BASE_URL to reflect this URL, but this caused the siwe-oidc container to constantly restart.
  4. host.docker.internal (https://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach) doesn't work because that address is only for use within the container, not from the host.

Conflicting domains in message and redirect when redirect_url contain no path

Symptom

Currently, if OIDC's redirect url has :port in it contains no path, e.g. "http:localhost", the OIDC process always failed with an error message:

Conflicting domains in message and redirect

even though the redirect url is specified as supported redirect url during client registration.

Cause

The direct cause is the message domain check.

Suggested resolution

Option 1: only check the host name bit of redirect url.
Option 2 (recommended): remove the message domain check as the Supported Redirect URLs mechanism has offer enough guard against rogue redirect url.

I am happy to make a patch to fix it. Please let me know your thoughts 🙂

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.