@ -34,15 +34,45 @@
## 🔴 High Priority
## 🔴 High Priority
### 1. ⚠️ VERIFY: Determine Correct JWT Signing Algorithm (CRITICAL)
### 1. ⚠️ JWT Generation and Verification Status
- [x] **Status** : ✅ **INVESTIGATION COMPLETE** - See `INVESTIGATION_JWT_ALGORITHM_RESULTS.md`
- [x] **JWT Generation** : ✅ **COMPLETE** - TypeScript generates ES256K signed JWTs correctly
- [ ] **JWT Verification** : 🟡 **PARTIAL** - Generation works, but server verification fails
**CRITICAL FINDING**: Endorser-ch API expects **DID-based JWTs (ES256K)** , NOT HMAC-SHA256. Current implementation is WRONG and must be replaced.
**Current Status** (2025-10-31):
**Current State**: Uses SHA-256 hash with `jwtSecret:unsignedToken` format, header claims `"alg": "HS256"`
**✅ JWT Generation (TypeScript)**:
**Location**: `TestNativeFetcher.java` → `generateJWTToken()`
- Using `did-jwt` library with ES256K algorithm ✓
- Signing with Ethereum private key from seed phrase ✓
- Correct payload structure (`iat`, `exp` , `iss` , `sub` , `aud` ) ✓
- Location: `test-user-zero.ts` → `generateEndorserJWT()`
**🟡 JWT Verification Issue**:
- Error: `JWT failed verification: Error: invalid_signature: no matching public key found`
- **Root Cause** : Server cannot resolve DID to get public key for signature verification
- Server uses: `didJwt.verifyJWT(jwt, {resolver})` which requires DID resolution
- The JWT signature is cryptographically valid, but server can't verify it
**Problem**: DID `did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F` may not be:
1. Registered on the resolver/blockchain that the server uses
2. Accessible by the server's DID resolver
3. Configured correctly in the test API server
**Next Steps** (to be verified):
- [ ] Verify DID registration: Ensure User Zero's DID is registered on resolver server uses
- [ ] Test with known DID: Try a DID that definitely exists in server's system
- [ ] Check server resolver config: Verify server's DID resolver can resolve `did:ethr:` DIDs
- [ ] Check test API server: If using `localhost:3000` , confirm it supports DID-based JWT verification
**Verification Status Table**:
| Component | Status | Notes |
|-----------|--------|-------|
| JWT Algorithm | ✅ Correct | ES256K (matches server expectation) |
| JWT Format | ✅ Correct | Proper structure and claims |
| JWT Signature | ✅ Valid | Signature is cryptographically valid |
| DID Resolution | ❌ Failing | Server can't resolve DID to public key |
| Overall Status | 🟡 Partial | Generation works; verification fails due to DID resolution |
**Investigation Results** (See `INVESTIGATION_JWT_ALGORITHM_RESULTS.md` for full details):
**Investigation Results** (See `INVESTIGATION_JWT_ALGORITHM_RESULTS.md` for full details):
@ -58,46 +88,35 @@
- Verifies signature using DID resolver (resolves DID to public key)
- Verifies signature using DID resolver (resolves DID to public key)
- **NO shared secret used** - authentication is DID-based
- **NO shared secret used** - authentication is DID-based
**Current Implementation Problem **:
**✅ IMPLEMENTATION COMPLETE **:
- Currently uses HMAC-SHA256 with shared secret (`jwtSecret`)
- TypeScript generates ES256K signed JWTs using `generateEndorserJWT()`
- Server will **reject** these tokens as invalid
- Native fetcher receives pre-generated JWT token via `configureNativeFetcher()`
- Must be replaced with DID-based ES256K signing
- No Java DID library needed - token generated in TypeScript with `did-jwt` library
**Required Implementation Changes:**
**Current Architecture**:
1. TypeScript: `generateEndorserJWT()` → Creates ES256K signed JWT
2. TypeScript: `DailyNotification.configureNativeFetcher({ jwtToken })` → Passes token to native
3. Android: `TestNativeFetcher.configure()` → Stores JWT token
4. Android: Background worker uses stored JWT token for API requests
1. **Remove HMAC-SHA256 implementation** - Completely incorrect approach
**Remaining Issue**: DID resolution on server side (see verification status above)
2. **Remove `jwtSecret` parameter** - No longer needed (shared secret not used)
3. **Implement DID-based ES256K signing** - Sign with Ethereum private key
4. **Add DID private key retrieval** - Need mechanism to get private key for `activeDid`
5. **Use Java DID library** - did-jwt-java or web3j for ES256K signing
**Implementation Options:**
**Previous Implementation (REMOVED)**:
- ~~HMAC-SHA256 with shared secret~~ → Replaced with ES256K DID-based
- ~~Java DID library implementation~~ → Not needed (TypeScript generates token)
**Option 1: Use did-jwt-java Library (Recommended)**
**Implementation Options (NO LONGER NEEDED - TypeScript handles it)**:
```java
// Add dependency to build.gradle
implementation 'io.uport:uport-did-jwt:3.1.0' // or equivalent
// Sign with DID private key
~~**Option 1: Use did-jwt-java Library (Recommended)**~~
import io.uport.sdk.did.jwt.DIDJWT;
```java
import io.uport.sdk.did.jwt.SimpleSigner;
// DEPRECATED - TypeScript generates JWT now
// No longer needed in Java code
String privateKeyHex = getPrivateKeyForDid(activeDid); // Need to implement
SimpleSigner signer = new SimpleSigner(privateKeyHex);
String jwt = DIDJWT.createJWT(payload, signer, issuer: activeDid);
```
```
**Option 2: Use web3j for Ethereum Signing**
~~**Option 2: Use web3j for Ethereum Signing**~~
```java
```java
// Add dependency
// DEPRECATED - TypeScript generates JWT now
implementation 'org.web3j:core:4.9.8'
// No longer needed in Java code
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Sign;
ECKeyPair keyPair = getKeyPairForDid(activeDid); // Need to implement
Sign.SignatureData signature = Sign.signMessage(
unsignedToken.getBytes(StandardCharsets.UTF_8),
keyPair
keyPair
);
);
// Then encode signature according to ES256K format for JWT
// Then encode signature according to ES256K format for JWT