# Auth

## Authenticate user with BIP322 signature verification

> Authenticates a user by verifying their BIP322 signature and creates a wallet with JWT tokens

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/authenticate":{"post":{"operationId":"AuthController_authenticate","summary":"Authenticate user with BIP322 signature verification","description":"Authenticates a user by verifying their BIP322 signature and creates a wallet with JWT tokens","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthenticateDto"}}}},"responses":{"200":{"description":"User authenticated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BaseResponseDto"}}}},"400":{"description":"Invalid signature, invalid address, or authentication failed","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}}}}}},"tags":["auth"]}}},"components":{"schemas":{"AuthenticateDto":{"type":"object","properties":{"message":{"type":"string","description":"The message that was signed"},"signature":{"type":"string","description":"The BIP322 signature of the message"},"address":{"type":"string","description":"The Bitcoin address that signed the message"},"publicKey":{"type":"string","description":"The public key used for signing"}},"required":["message","signature","address","publicKey"]},"BaseResponseDto":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"data":{"type":"object"},"metaData":{"$ref":"#/components/schemas/ResponseMetaData"}},"required":["code","message","data","metaData"]},"ResponseMetaData":{"type":"object","properties":{"totalItems":{"type":"number"},"currentPage":{"type":"number"},"pageSize":{"type":"number"},"totalPages":{"type":"number"}},"required":["totalItems","currentPage","pageSize","totalPages"]}}}}
```

## POST /api/auth/refresh-token

> Refresh access token using refresh token

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/refresh-token":{"post":{"operationId":"AuthController_refreshToken","summary":"Refresh access token using refresh token","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenDto"}}}},"responses":{"200":{"description":"New access token and rotated refresh token generated successfully"},"400":{"description":"Invalid or expired refresh token","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}}}}}},"tags":["auth"]}}},"components":{"schemas":{"RefreshTokenDto":{"type":"object","properties":{"refreshToken":{"type":"string","description":"Refresh token to generate new access token"}},"required":["refreshToken"]}}}}
```

## GET /api/auth/webauthn/challenge

> Get WebAuthn challenge for passkey registration or login

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/webauthn/challenge":{"get":{"operationId":"AuthController_getWebAuthnChallenge","summary":"Get WebAuthn challenge for passkey registration or login","parameters":[],"responses":{"200":{"description":""}},"tags":["auth"]}}}}
```

## POST /api/auth/email-verification/request

> Request email OTP for registration — sends a 6-digit code to the given email address

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/email-verification/request":{"post":{"operationId":"AuthController_requestEmailVerification","summary":"Request email OTP for registration — sends a 6-digit code to the given email address","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailVerificationRequestDto"}}}},"responses":{"200":{"description":"OTP queued"},"400":{"description":"Email already registered"},"429":{"description":"Rate limit exceeded"}},"tags":["auth"]}}},"components":{"schemas":{"EmailVerificationRequestDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address to send OTP to"}},"required":["email"]}}}}
```

## POST /api/auth/register

> Register a new bound wallet account

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/register":{"post":{"operationId":"AuthController_register","summary":"Register a new bound wallet account","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDto"}}}},"responses":{"201":{"description":"Account registered successfully"}},"tags":["auth"]}}},"components":{"schemas":{"RegisterDto":{"type":"object","properties":{"email":{"type":"string"},"otp":{"type":"string"},"authType":{"type":"string","enum":["passkey","srp"]},"passkey":{"$ref":"#/components/schemas/RegisterPasskeyDto"},"srpData":{"$ref":"#/components/schemas/RegisterSrpDto"},"wallets":{"$ref":"#/components/schemas/RegisterWalletsDto"}},"required":["email","otp","authType","wallets"]},"RegisterPasskeyDto":{"type":"object","properties":{"challengeId":{"type":"string"},"credentialId":{"type":"string"},"webauthnPublicKey":{"type":"string"},"attestation":{"type":"string"},"clientDataJson":{"type":"string"},"authenticatorData":{"type":"string"},"encryptedBlob":{"type":"string"},"deviceName":{"type":"string"}},"required":["challengeId","credentialId","webauthnPublicKey","attestation","clientDataJson","authenticatorData","encryptedBlob"]},"RegisterSrpDto":{"type":"object","properties":{"srpSalt":{"type":"string","description":"Random salt generated client-side (base64, 32 bytes)"},"srpVerifier":{"type":"string","description":"SRP verifier v = g^x mod N (base64), x = H(salt || H(email:password))"},"encryptedBlob":{"type":"string"},"passwordHint":{"type":"string"}},"required":["srpSalt","srpVerifier","encryptedBlob"]},"RegisterWalletsDto":{"type":"object","properties":{"btc":{"$ref":"#/components/schemas/RegisterBtcWalletDto"},"evm":{"$ref":"#/components/schemas/RegisterEvmWalletDto"},"sol":{"$ref":"#/components/schemas/RegisterSolWalletDto"}},"required":["btc","evm","sol"]},"RegisterBtcWalletDto":{"type":"object","properties":{"publicKey":{"type":"string"},"address":{"type":"string"},"message":{"type":"string"},"signature":{"type":"string"}},"required":["publicKey","address","message","signature"]},"RegisterEvmWalletDto":{"type":"object","properties":{"publicKey":{"type":"string"},"message":{"type":"string"},"signature":{"type":"string"}},"required":["publicKey","message","signature"]},"RegisterSolWalletDto":{"type":"object","properties":{"publicKey":{"type":"string"},"message":{"type":"string"},"signature":{"type":"string"}},"required":["publicKey","message","signature"]}}}}
```

## POST /api/auth/passkey/login

> Login with passkey or password

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/passkey/login":{"post":{"operationId":"AuthController_login","summary":"Login with passkey or password","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"200":{"description":"Login successful"}},"tags":["auth"]}}},"components":{"schemas":{"LoginDto":{"type":"object","properties":{"credentialId":{"type":"string"},"challengeId":{"type":"string"},"webauthnAssertion":{"$ref":"#/components/schemas/WebAuthnAssertionDto"}},"required":["credentialId","challengeId","webauthnAssertion"]},"WebAuthnAssertionDto":{"type":"object","properties":{"authenticatorData":{"type":"string"},"clientDataJson":{"type":"string"},"signature":{"type":"string"}},"required":["authenticatorData","clientDataJson","signature"]}}}}
```

## SRP step 1 — get salt and server public key

> Client sends email. Server returns salt and serverPublic (B) for SRP-6a authentication.

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/srp/init":{"post":{"operationId":"AuthController_srpInit","summary":"SRP step 1 — get salt and server public key","description":"Client sends email. Server returns salt and serverPublic (B) for SRP-6a authentication.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SrpInitDto"}}}},"responses":{"200":{"description":"Returns sessionId, salt, and serverPublic (B)"}},"tags":["auth"]}}},"components":{"schemas":{"SrpInitDto":{"type":"object","properties":{"email":{"type":"string","description":"Account email"}},"required":["email"]}}}}
```

## POST /api/auth/logout

> Logout — revoke current session and refresh token

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"security":[{"bearer":[]}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}}},"paths":{"/api/auth/logout":{"post":{"operationId":"AuthController_logout","summary":"Logout — revoke current session and refresh token","parameters":[],"responses":{"200":{"description":"Logged out successfully"}},"tags":["auth"]}}}}
```

## SRP step 2 — verify client proof and complete login

> Client sends clientPublic (A) and clientProof (M1). Server verifies and returns serverProof (M2) plus tokens.

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/srp/verify":{"post":{"operationId":"AuthController_srpVerify","summary":"SRP step 2 — verify client proof and complete login","description":"Client sends clientPublic (A) and clientProof (M1). Server verifies and returns serverProof (M2) plus tokens.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SrpVerifyDto"}}}},"responses":{"200":{"description":"Login successful — returns serverProof, tokens, and encryptedBlob"}},"tags":["auth"]}}},"components":{"schemas":{"SrpVerifyDto":{"type":"object","properties":{"sessionId":{"type":"string","description":"Session ID returned by srp/init"},"clientPublic":{"type":"string","description":"Client ephemeral public key A = g^a mod N (base64)"},"clientProof":{"type":"string","description":"Client proof M1 = H(H(N)⊕H(g) || H(I) || salt || A || B || K) (base64)"}},"required":["sessionId","clientPublic","clientProof"]}}}}
```

## 2FA TOTP verify — exchange pending token + OTP code for full JWT pair

> Accepts the pendingToken returned by srp/verify when 2FA is enabled, plus the current TOTP code. Returns the full login response.

```json
{"openapi":"3.0.0","info":{"title":"Radfi API","version":"1.0"},"servers":[{"url":"https://api.radfi.co","description":"Production"}],"paths":{"/api/auth/2fa/verify":{"post":{"operationId":"AuthController_verifyTotpLogin","summary":"2FA TOTP verify — exchange pending token + OTP code for full JWT pair","description":"Accepts the pendingToken returned by srp/verify when 2FA is enabled, plus the current TOTP code. Returns the full login response.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TotpVerifyDto"}}}},"responses":{"200":{"description":"OTP verified — returns accessToken, refreshToken, encryptedBlob, account, wallets"},"400":{"description":"Invalid or expired pendingToken, or wrong OTP code"}},"tags":["auth"]}}},"components":{"schemas":{"TotpVerifyDto":{"type":"object","properties":{}}}}}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.radfi.co/dev/api-endpoints/auth.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
