Skip to content

Commit 3b214f6

Browse files
authored
Merge pull request #35 from pattern-tech/feat/siwe-verify
`/auth/verify` API
2 parents 4dd958d + cc22659 commit 3b214f6

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

api/src/auth/routers/auth_router.py

+29
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
AuthService,
44
LoginInput,
55
RegisterInput,
6+
VerifyInput
67
)
78
from src.db.sql_alchemy import Database
89
from src.util.response import global_response
@@ -19,6 +20,7 @@
1920
"/register",
2021
summary="User Registration",
2122
description="Register a new user with email and password.",
23+
deprecated=True
2224
)
2325
def register(input: RegisterInput, db: Session = Depends(database.get_db)):
2426
"""
@@ -42,6 +44,7 @@ def register(input: RegisterInput, db: Session = Depends(database.get_db)):
4244
"/login",
4345
summary="User Login",
4446
description="Authenticate a user with email and password.",
47+
deprecated=True,
4548
)
4649
def login(input: LoginInput, db: Session = Depends(database.get_db)):
4750
"""
@@ -59,3 +62,29 @@ def login(input: LoginInput, db: Session = Depends(database.get_db)):
5962
"access_token": token,
6063
}
6164
)
65+
66+
67+
@router.post(
68+
"/verify",
69+
summary="Verify a Signature",
70+
description="Verify a signature according to SIWE spec",
71+
)
72+
def verify(input: VerifyInput):
73+
"""
74+
Verify a signature according to SIWE spec and return an access token
75+
76+
- **message**: A SIWE message
77+
- **signature**: User's signature for the message
78+
"""
79+
verification_result = auth.verify_signature(
80+
input.message, input.signature)
81+
82+
payload = {"id": "{}:{}".format(
83+
verification_result.chain_id, verification_result.address)}
84+
85+
token = generate_access_token(data=payload)
86+
return global_response(
87+
{
88+
"access_token": token,
89+
}
90+
)

api/src/auth/services/auth_service.py

+41
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from src.auth.utils.bcrypt_helper import hash_password, verify_password
66
from src.db.models import UserModel
77
from src.db.sql_alchemy import Database
8+
from siwe import SiweMessage
89

910
database = Database()
1011

@@ -31,6 +32,15 @@ class LoginInput(BaseModel):
3132
)
3233

3334

35+
class VerifyInput(BaseModel):
36+
message: str = Field(
37+
..., example="0x0...", description="The SIWE message"
38+
)
39+
signature: str = Field(
40+
..., example="0x0...", description="User's signature for a message"
41+
)
42+
43+
3444
class AuthService:
3545
"""
3646
Service class for handling user authentication and registration logic.
@@ -91,3 +101,34 @@ def authenticate_user(self, email: str, password: str, db: Session):
91101
raise HTTPException(status_code=401, detail="Incorrect email or password")
92102

93103
return user
104+
105+
def verify_signature(self, message: str, signature: str):
106+
"""
107+
Verify a signature according to SIWE spec
108+
109+
Args:
110+
message (str): A SIWE message
111+
signature (str): User's signature for the message
112+
113+
Returns:
114+
VerificationResult: The result of the verification, containing the address and chain id of the signing wallet
115+
116+
Raises:
117+
HTTPException: If message cannot be parsed or verified
118+
"""
119+
120+
try:
121+
siwe_message = SiweMessage.from_message(message)
122+
siwe_message.verify(signature)
123+
except ValueError:
124+
# ValueError is raised if message is invalid according to SIWE
125+
raise HTTPException(
126+
status_code=400, detail="The provided message is not a valid SIWE message")
127+
except:
128+
raise HTTPException(
129+
status_code=401, detail="Signature is not valid")
130+
131+
return {
132+
"chain_id": siwe_message.chain_id,
133+
"address": siwe_message.address,
134+
}

0 commit comments

Comments
 (0)