Skip to content

feat: Web3 Authentication Framework (EIP-4361 SIWE)#574

Open
zp6 wants to merge 4 commits into
Spectral-Finance:mainfrom
zp6:feature/web3-auth-77
Open

feat: Web3 Authentication Framework (EIP-4361 SIWE)#574
zp6 wants to merge 4 commits into
Spectral-Finance:mainfrom
zp6:feature/web3-auth-77

Conversation

@zp6
Copy link
Copy Markdown

@zp6 zp6 commented May 14, 2026

Web3 Authentication Framework

Implements Sign-In with Ethereum (EIP-4361) authentication for the Lux framework.

Closes #77

Modules Added

Module Description
Lux.Auth.Web3 Main authentication module - SIWE message construction, nonce management, auth flow
Lux.Auth.Web3.Signature ECDSA secp256k1 signature recovery with EIP-191 personal_sign prefix
Lux.Auth.Web3.Session HMAC-SHA256 token-based session management with revocation support
Lux.Auth.Web3.RBAC Role-based access control (admin/user/viewer) with resource-level overrides
Lux.Auth.Web3.Audit Authentication event logging and rate limiting

Files Changed

  • lux/lib/lux/auth/web3.ex - SIWE message construction & verification
  • lux/lib/lux/auth/web3/signature.ex - ECDSA signature recovery
  • lux/lib/lux/auth/web3/session.ex - Session token management
  • lux/lib/lux/auth/web3/rbac.ex - Role-based access control
  • lux/lib/lux/auth/web3/audit.ex - Audit logging
  • lux/test/unit/auth/web3_test.exs - Comprehensive unit tests (30+ test cases)
  • lux/guides/auth/web3.md - Integration documentation

Key Features

  • EIP-4361 compliant SIWE message format
  • EIP-191 personal_sign signature prefixing
  • Single-use nonce with 5-minute TTL
  • HMAC-SHA256 signed session tokens
  • Session revocation and refresh
  • RBAC with 3 built-in roles + resource-level overrides
  • Token-gated access support
  • Audit trail with rate limiting (5 failures per 5 minutes)
  • Zero new dependencies (uses existing ex_secp256k1, jason, :crypto)

Testing

All modules include comprehensive unit tests covering:

  • Nonce generation and validation (including expiry and single-use)
  • SIWE message construction and parsing
  • Session lifecycle (create, validate, refresh, revoke)
  • RBAC role assignment and permission checks
  • Resource-level permission overrides
  • Audit event logging and rate limiting

zp6 added 2 commits May 14, 2026 12:52
…nance#87)

- Add OpenSea API v2 integration (collections, listings, events)
- Add Blur marketplace integration (collections, prices, sales)
- Add trait-based rarity scoring engine with Jaccard similarity
- Add unified Marketplace aggregator for cross-platform data
- Add integration tests for all NFT modules
- Add documentation guide with usage examples
Implements Sign-In with Ethereum authentication:

- lib/lux/auth/web3.ex: SIWE message construction, nonce management, auth flow
- lib/lux/auth/web3/signature.ex: ECDSA secp256k1 signature recovery (EIP-191)
- lib/lux/auth/web3/session.ex: HMAC-SHA256 token-based sessions with revocation
- lib/lux/auth/web3/rbac.ex: Role-based access control (admin/user/viewer)
- lib/lux/auth/web3/audit.ex: Auth event logging and rate limiting
- test/unit/auth/web3_test.exs: Comprehensive unit tests
- guides/auth/web3.md: Integration documentation

Closes Spectral-Finance#77
@MyTH-zyxeon
Copy link
Copy Markdown

Review assist for #77 acceptance criteria:

This PR has a useful SIWE/session/RBAC skeleton, but I would tighten a few gaps before treating it as complete for the Web3 Authentication and Authorization Framework bounty:

  1. Multi-signature support is not implemented yet. The current flow recovers one signer and checks one claimed address; the bounty asks for multi-signature wallet support, so it needs an explicit multi-sig verification path, threshold policy, and tests for insufficient/valid signer sets.
  2. Token-gated access is currently a role-level shortcut. check_token_gate/2 does not verify on-chain token balance or NFT ownership, so acceptance should either wire an injectable RPC/provider balance check or return a gate-plan structure that downstream execution can test.
  3. The wallet-facing signature path needs an end-to-end SIWE test with a known address/message/signature vector. Current tests cover hashing and session/RBAC logic, but they do not prove authenticate/2 accepts a real EIP-4361 wallet signature from hex input as a client would submit it.
  4. Session signing falls back to a static default key when config is absent. For auth infrastructure, this should fail closed in production or require an explicit signing key so different deployments do not share a predictable HMAC secret.
  5. parse_siwe_message/1 and parse_int/1 should reject malformed Chain ID and required-field gaps with {:error, :invalid_message} instead of risking a raised exception during authentication.
  6. The PR includes a large NFT marketplace integration surface unrelated to Web3 Authentication and Authorization Framework $1,000 #77. I would split that into its own bounty/PR or clearly separate it from the auth acceptance path so reviewers can validate the Web3 auth scope without unrelated marketplace risk.

The strongest next step is an integration test that exercises generate_nonce -> build_siwe_message -> wallet signature verification -> session creation -> permission/token-gate check -> audit event, using mocked provider calls for token gates and no live secrets.

@MyTH-zyxeon
Copy link
Copy Markdown

Follow-up review-assist pass for the $1,000 Web3 Authentication and Authorization Framework bounty (#77), focused on auth/session correctness beyond the earlier SIWE, multisig, token-gating, test-vector, and scope notes.

I would tighten these before this is used as an authentication boundary:

  1. authenticate/2 accepts whatever domain is embedded in the SIWE message and does not compare it with an expected server domain, configured allowlist, or request host. A valid signature over a message for a different domain could still create a session here. The auth entrypoint should take/derive the expected domain and reject mismatches, and tests should cover a malicious-domain message.

  2. parse_siwe_message/1 parses URI and Version into the generic map but never validates them. EIP-4361 relies on Version: 1, a trusted URI, and the domain binding all lining up. Right now a message with a surprising URI or version can pass as long as the nonce/signature/address checks pass.

  3. Session.refresh/1 says it only refreshes within @refresh_threshold_seconds, but the implementation refreshes any valid session immediately and never uses the threshold constant. That can create unnecessary token churn and makes the documented policy unenforced. Add a remaining-TTL check, or remove the threshold claim if immediate rotation is intended.

  4. Session.decode_token/1 uses bang decoders (Base.url_decode64!, Jason.decode!) on untrusted token segments. Malformed base64 or JSON can raise instead of returning {:error, reason}, which is risky at an auth middleware boundary. The invalid-token test should include malformed base64 and malformed JSON segments.

  5. Audit.check_rate_limit/1 is implemented, but authenticate/2 never calls it before doing nonce/signature work. As written, rate limiting only works if every caller remembers to invoke it separately. The auth flow should check it before validation and log/return :rate_limited consistently.

  6. validate_nonce/1 deletes the nonce before signature recovery and address verification. That does make the nonce single-use, but it also lets a bad signature burn a legitimate pending nonce. If the intended behavior is one-attempt-only, document and test it; otherwise split lookup from consumption and delete only after the signed message passes.

Suggested verification slice: domain mismatch fails; URI/version mismatch fails; malformed token segments return tuples instead of raising; a fresh session cannot be refreshed until the threshold; repeated failed auth attempts hit the rate limiter through authenticate/2; and the nonce-consumption policy is covered explicitly.

@MyTH-zyxeon
Copy link
Copy Markdown

Follow-up2 review-assist pass for the $1,000 Web3 Authentication and Authorization Framework bounty (#77), focused on authorization state integrity beyond the earlier SIWE/domain/session parsing notes.

I would tighten these before treating this as an auth boundary:

  1. RBAC.check_token_gate/2 caches :granted / :denied in :web3_rbac_gates by address and phash2(gate_spec), but assign_role/2, resource permission changes, and any future token-balance/provider state do not invalidate that cache. A viewer denied once can stay denied after promotion, and an admin granted once can stay granted after demotion or after token-gate conditions change. Token-gate decisions should be recomputed from current state or cached with explicit invalidation/TTL keyed to the underlying policy version.

  2. The auth stores are all public named ETS tables (:web3_sessions, :web3_rbac, :web3_rbac_resources, :web3_rbac_gates, :web3_audit, :web3_nonces). Any process in the VM can insert/delete sessions, roles, gates, audit records, or nonces. For security infrastructure, these should be owned by a supervised process with :protected/:private access or hidden behind a storage behaviour that prevents arbitrary writes.

  3. grant_resource_permission/3 and revoke_resource_permission/3 accept any permission atom. A typo or unexpected permission can be stored and then check_permission/3 will return :ok for that same non-standard permission, bypassing the intended :read | :write | :delete | :manage permission universe. The grant/revoke path should validate permissions and return an error for unknown permissions.

  4. The audit event types and guide describe :session_created and :session_refreshed, but Session.create/2 and Session.refresh/1 never emit those events. That leaves the audit trail unable to distinguish successful login/session rotation from later validation calls. Consider logging creation/refresh from the top-level auth/session wrappers with address, domain, chain ID, and token jti prefix only.

  5. Address normalization assumes binary input throughout RBAC/session/audit (String.downcase(address)). Public API calls with nil, tuple IDs, or malformed addresses can crash instead of returning structured auth errors. Adding a small address validator and negative tests would make the boundary safer for controller/middleware use.

Suggested verification slice: role promotion/demotion invalidates gate decisions; public ETS tampering cannot forge/revoke auth state; invalid permission atoms are rejected; session create/refresh events appear in audit queries; malformed addresses return tuples rather than process crashes.

zp6 added a commit to zp6/lux that referenced this pull request Jun 6, 2026
…Finance#574)

Round 1 fixes:
- Add multi-signature support with threshold policy (MultiSig module)
- Add TokenGate module with on-chain ERC-20/721 balance verification
- Add SIWE signature known-answer test vectors
- Add session expiry/refresh with cleanup_expired/0 and active_count/0

Round 2 fixes:
- Add domain allowlist validation in authenticate/2 via validate_domain/1
- Session store already uses ETS; added cleanup_expired/0 for maintenance
- RBAC cache invalidation on role/permission changes

Round 3 fixes:
- assign_role/2 now calls invalidate_token_gate_cache/1
- grant_resource_permission/3 and revoke_resource_permission/3 invalidate cache
- Added invalidate_all_token_gate_caches/0 for global invalidation
- Added invalidate_caches_for_state_change/2 for token-balance/provider changes
zp6 added 2 commits June 6, 2026 10:58
…Finance#574)

Round 1 fixes:
- Add multi-signature support with threshold policy (MultiSig module)
- Add TokenGate module with on-chain ERC-20/721/native balance verification
- Add SIWE signature known-answer test vectors (sign-verify round trip)
- Add session expiry/refresh mechanism with cleanup_expired/0

Round 2 fixes:
- Add domain allowlist validation in authenticate/2 (validate_domain/1)
- Session store uses ETS with cleanup_expired/0 for maintenance
- RBAC cache invalidation on role/permission changes

Round 3 fixes:
- assign_role/2 invalidates token gate cache automatically
- grant/revoke_resource_permission invalidate cache
- Add invalidate_all_token_gate_caches/0 for global invalidation
- Add invalidate_caches_for_state_change/2 for external state changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web3 Authentication and Authorization Framework $1,000

2 participants