or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mddevice-authentication.mdgroup-management.mdhttp-integration.mdindex.mdmfa.mdpassword-management.mdsrp-authentication.mduser-management.md

device-authentication.mddocs/

0

# Device Authentication

1

2

Device tracking and authentication support for AWS Cognito User Pools, enabling device-based security features including device confirmation, status management, and device-specific authentication flows. Device authentication adds an additional layer of security by tracking and managing trusted devices.

3

4

## Capabilities

5

6

### Device Confirmation

7

8

Confirm and register devices for trusted device tracking and enhanced security.

9

10

```python { .api }

11

def confirm_device(self, tokens: dict, device_name: str = None) -> tuple:

12

"""

13

Confirm a device for device tracking and authentication.

14

15

Args:

16

tokens (dict): Authentication result tokens containing device metadata

17

device_name (str, optional): Friendly name for device (defaults to hostname)

18

19

Returns:

20

tuple: (response, device_password)

21

- response: HTTP response from device confirmation

22

- device_password: Generated device password for future authentication

23

24

Actions:

25

- Registers device with Cognito

26

- Generates device-specific credentials

27

- Sets up device for remembered authentication

28

- Stores device keys and metadata

29

30

Sets instance attributes:

31

- access_token: Token from authentication result

32

- device_key: Unique device identifier

33

- device_group_key: Device group identifier

34

- device_name: Friendly device name

35

"""

36

```

37

38

**Usage Example:**

39

40

```python

41

from pycognito.aws_srp import AWSSRP

42

43

# Authenticate user and get tokens with device metadata

44

aws_srp = AWSSRP(

45

username='user@example.com',

46

password='password',

47

pool_id='us-east-1_example',

48

client_id='your-client-id'

49

)

50

51

# Authenticate and get tokens

52

tokens = aws_srp.authenticate_user()

53

54

# Check if device confirmation is needed

55

if 'NewDeviceMetadata' in tokens.get('AuthenticationResult', {}):

56

print("New device detected - confirming device")

57

58

# Confirm device with friendly name

59

response, device_password = aws_srp.confirm_device(

60

tokens,

61

device_name="John's iPhone"

62

)

63

64

print(f"Device confirmed! Device password: {device_password}")

65

print(f"Device key: {aws_srp.device_key}")

66

67

# Store device credentials securely for future use

68

store_device_credentials(aws_srp.device_key, device_password)

69

```

70

71

### Device Status Management

72

73

Update device status to control device behavior and memory settings.

74

75

```python { .api }

76

def update_device_status(self, is_remembered: bool, access_token: str, device_key: str) -> str:

77

"""

78

Update device remembered status.

79

80

Args:

81

is_remembered (bool): Whether device should be remembered

82

access_token (str): Valid access token

83

device_key (str): Device key from device confirmation

84

85

Returns:

86

str: Response status from update operation

87

88

Device status options:

89

- remembered: Device is trusted and remembers user

90

- not_remembered: Device requires full authentication each time

91

92

Use cases:

93

- Mark personal devices as remembered

94

- Mark public/shared devices as not remembered

95

- Revoke device trust due to security concerns

96

"""

97

```

98

99

**Usage Example:**

100

101

```python

102

# Mark device as remembered (trusted)

103

response = aws_srp.update_device_status(

104

is_remembered=True,

105

access_token=user.access_token,

106

device_key=device_key

107

)

108

print(f"Device marked as remembered: {response}")

109

110

# Later, mark device as not remembered (untrusted)

111

response = aws_srp.update_device_status(

112

is_remembered=False,

113

access_token=user.access_token,

114

device_key=device_key

115

)

116

print(f"Device marked as not remembered: {response}")

117

```

118

119

### Device Forgetting

120

121

Remove device trust and credentials from the system.

122

123

```python { .api }

124

def forget_device(self, access_token: str, device_key: str) -> str:

125

"""

126

Forget/remove a device from trusted devices.

127

128

Args:

129

access_token (str): Valid access token

130

device_key (str): Device key to forget

131

132

Returns:

133

str: Response status from forget operation

134

135

Actions:

136

- Removes device from trusted device list

137

- Invalidates device-specific credentials

138

- Forces full authentication on next login

139

- Clears device memory and tracking

140

141

Use cases:

142

- Device is lost or stolen

143

- User no longer uses the device

144

- Security incident requires device removal

145

- User explicitly removes device trust

146

"""

147

```

148

149

**Usage Example:**

150

151

```python

152

# Forget a lost or stolen device

153

response = aws_srp.forget_device(

154

access_token=user.access_token,

155

device_key=lost_device_key

156

)

157

print(f"Device forgotten: {response}")

158

159

# Device will require full authentication next time

160

```

161

162

### Device-Enhanced Authentication

163

164

Authenticate with device-specific credentials for enhanced security and user experience.

165

166

```python { .api }

167

class AWSSRP:

168

def __init__(self, username: str, password: str, pool_id: str, client_id: str,

169

device_key: str = None, device_group_key: str = None,

170

device_password: str = None, **kwargs):

171

"""

172

Initialize AWSSRP with device authentication support.

173

174

Args:

175

username (str): Username

176

password (str): User password

177

pool_id (str): User pool ID

178

client_id (str): Client ID

179

device_key (str, optional): Device key from device confirmation

180

device_group_key (str, optional): Device group key

181

device_password (str, optional): Device password

182

183

Note:

184

For device authentication, either all device parameters must be provided

185

or none at all. Partial device parameters will raise ValueError.

186

"""

187

188

def authenticate_user(self, client=None, client_metadata: dict = None) -> dict:

189

"""

190

Authenticate user with optional device authentication.

191

192

Returns:

193

dict: Authentication tokens and device metadata

194

195

Flow:

196

1. Standard SRP authentication

197

2. If device keys provided, performs device authentication

198

3. Returns tokens with device confirmation if new device

199

4. Handles device challenges automatically

200

"""

201

```

202

203

**Usage Example:**

204

205

```python

206

# Authenticate with remembered device

207

aws_srp = AWSSRP(

208

username='user@example.com',

209

password='password',

210

pool_id='us-east-1_example',

211

client_id='your-client-id',

212

device_key='stored-device-key',

213

device_group_key='stored-device-group-key',

214

device_password='stored-device-password'

215

)

216

217

try:

218

# Authentication with device credentials

219

tokens = aws_srp.authenticate_user()

220

print("Authentication successful with device credentials!")

221

222

except Exception as e:

223

print(f"Device authentication failed: {e}")

224

# Fall back to standard authentication

225

aws_srp_fallback = AWSSRP(

226

username='user@example.com',

227

password='password',

228

pool_id='us-east-1_example',

229

client_id='your-client-id'

230

)

231

tokens = aws_srp_fallback.authenticate_user()

232

```

233

234

## Usage Patterns

235

236

### Complete Device Registration Flow

237

238

```python

239

def register_device(username, password, device_name):

240

"""Complete device registration and confirmation flow."""

241

242

# Step 1: Initial authentication

243

aws_srp = AWSSRP(

244

username=username,

245

password=password,

246

pool_id='your-pool-id',

247

client_id='your-client-id'

248

)

249

250

# Step 2: Authenticate and check for new device

251

tokens = aws_srp.authenticate_user()

252

253

auth_result = tokens.get('AuthenticationResult', {})

254

255

if 'NewDeviceMetadata' in auth_result:

256

print("New device detected - setting up device authentication")

257

258

# Step 3: Confirm device

259

response, device_password = aws_srp.confirm_device(tokens, device_name)

260

261

if response.status_code == 200:

262

print("Device confirmed successfully!")

263

264

# Step 4: Mark as remembered

265

aws_srp.update_device_status(

266

is_remembered=True,

267

access_token=auth_result['AccessToken'],

268

device_key=aws_srp.device_key

269

)

270

271

# Step 5: Store device credentials securely

272

device_credentials = {

273

'device_key': aws_srp.device_key,

274

'device_group_key': aws_srp.device_group_key,

275

'device_password': device_password,

276

'device_name': device_name

277

}

278

279

# Store in secure storage (keychain, encrypted file, etc.)

280

save_device_credentials(username, device_credentials)

281

282

print(f"Device '{device_name}' registered and remembered")

283

return device_credentials

284

285

else:

286

print(f"Device confirmation failed: {response}")

287

return None

288

else:

289

print("No new device metadata - device may already be registered")

290

return None

291

292

# Usage

293

device_creds = register_device('user@example.com', 'password', 'My Laptop')

294

```

295

296

### Device-Aware Authentication Manager

297

298

```python

299

class DeviceAwareAuth:

300

"""Authentication manager with device support."""

301

302

def __init__(self, pool_id, client_id):

303

self.pool_id = pool_id

304

self.client_id = client_id

305

306

def authenticate(self, username, password, device_credentials=None):

307

"""Authenticate with optional device credentials."""

308

309

if device_credentials:

310

# Try device-enhanced authentication first

311

try:

312

aws_srp = AWSSRP(

313

username=username,

314

password=password,

315

pool_id=self.pool_id,

316

client_id=self.client_id,

317

device_key=device_credentials['device_key'],

318

device_group_key=device_credentials['device_group_key'],

319

device_password=device_credentials['device_password']

320

)

321

322

tokens = aws_srp.authenticate_user()

323

return tokens, "DEVICE_AUTH_SUCCESS"

324

325

except Exception as e:

326

print(f"Device authentication failed: {e}")

327

# Fall through to standard authentication

328

329

# Standard authentication

330

aws_srp = AWSSRP(

331

username=username,

332

password=password,

333

pool_id=self.pool_id,

334

client_id=self.client_id

335

)

336

337

tokens = aws_srp.authenticate_user()

338

339

# Check if device registration is needed

340

if 'NewDeviceMetadata' in tokens.get('AuthenticationResult', {}):

341

return tokens, "NEW_DEVICE_DETECTED"

342

else:

343

return tokens, "STANDARD_AUTH_SUCCESS"

344

345

def setup_device(self, tokens, device_name, remember=True):

346

"""Set up device after authentication."""

347

348

# This would typically be called by the same AWSSRP instance

349

# that performed authentication

350

aws_srp = AWSSRP(

351

username="", password="", # Not needed for device operations

352

pool_id=self.pool_id,

353

client_id=self.client_id

354

)

355

356

response, device_password = aws_srp.confirm_device(tokens, device_name)

357

358

if response.status_code == 200 and remember:

359

aws_srp.update_device_status(

360

is_remembered=True,

361

access_token=tokens['AuthenticationResult']['AccessToken'],

362

device_key=aws_srp.device_key

363

)

364

365

return {

366

'device_key': aws_srp.device_key,

367

'device_group_key': aws_srp.device_group_key,

368

'device_password': device_password,

369

'device_name': device_name

370

}

371

372

# Usage

373

auth_manager = DeviceAwareAuth('pool-id', 'client-id')

374

375

# Load stored device credentials

376

device_creds = load_device_credentials('user@example.com')

377

378

# Authenticate

379

tokens, status = auth_manager.authenticate(

380

'user@example.com',

381

'password',

382

device_creds

383

)

384

385

if status == "NEW_DEVICE_DETECTED":

386

# Set up new device

387

new_device_creds = auth_manager.setup_device(

388

tokens,

389

"My New Device",

390

remember=True

391

)

392

save_device_credentials('user@example.com', new_device_creds)

393

print("New device set up successfully!")

394

395

elif status == "DEVICE_AUTH_SUCCESS":

396

print("Authenticated with trusted device!")

397

398

elif status == "STANDARD_AUTH_SUCCESS":

399

print("Standard authentication successful!")

400

```

401

402

### Device Management Dashboard

403

404

```python

405

def device_management_interface(username, access_token):

406

"""Interactive device management interface."""

407

408

print(f"\n=== Device Management for {username} ===")

409

print("1. List trusted devices")

410

print("2. Forget a device")

411

print("3. Update device status")

412

print("4. Register new device")

413

414

choice = input("Select option (1-4): ")

415

416

if choice == "1":

417

# List devices (would require additional API calls)

418

print("Trusted devices:")

419

devices = get_user_devices(username) # Custom function

420

for device in devices:

421

print(f"- {device['name']} ({device['key']})")

422

423

elif choice == "2":

424

# Forget device

425

device_key = input("Enter device key to forget: ")

426

427

aws_srp = AWSSRP(

428

username="", password="",

429

pool_id='pool-id', client_id='client-id'

430

)

431

432

response = aws_srp.forget_device(access_token, device_key)

433

print(f"Device forgotten: {response}")

434

435

elif choice == "3":

436

# Update device status

437

device_key = input("Enter device key: ")

438

remember = input("Remember device? (y/n): ").lower() == 'y'

439

440

aws_srp = AWSSRP(

441

username="", password="",

442

pool_id='pool-id', client_id='client-id'

443

)

444

445

response = aws_srp.update_device_status(

446

is_remembered=remember,

447

access_token=access_token,

448

device_key=device_key

449

)

450

print(f"Device status updated: {response}")

451

452

elif choice == "4":

453

print("Please authenticate on the new device to register it")

454

455

# Usage after authentication

456

device_management_interface('user@example.com', user.access_token)

457

```

458

459

### Secure Device Storage

460

461

```python

462

import json

463

import keyring

464

from cryptography.fernet import Fernet

465

466

class SecureDeviceStorage:

467

"""Secure storage for device credentials."""

468

469

def __init__(self, service_name="MyApp"):

470

self.service_name = service_name

471

472

def _get_encryption_key(self, username):

473

"""Get or create encryption key for user."""

474

key_name = f"{username}_device_key"

475

476

# Try to get existing key

477

key = keyring.get_password(self.service_name, key_name)

478

479

if not key:

480

# Generate new key

481

key = Fernet.generate_key().decode()

482

keyring.set_password(self.service_name, key_name, key)

483

484

return key.encode()

485

486

def store_device_credentials(self, username, credentials):

487

"""Store device credentials securely."""

488

encryption_key = self._get_encryption_key(username)

489

fernet = Fernet(encryption_key)

490

491

# Encrypt credentials

492

credentials_json = json.dumps(credentials)

493

encrypted_credentials = fernet.encrypt(credentials_json.encode())

494

495

# Store in keyring

496

cred_name = f"{username}_device_credentials"

497

keyring.set_password(

498

self.service_name,

499

cred_name,

500

encrypted_credentials.decode()

501

)

502

503

def load_device_credentials(self, username):

504

"""Load device credentials securely."""

505

try:

506

encryption_key = self._get_encryption_key(username)

507

fernet = Fernet(encryption_key)

508

509

# Get encrypted credentials

510

cred_name = f"{username}_device_credentials"

511

encrypted_credentials = keyring.get_password(

512

self.service_name,

513

cred_name

514

)

515

516

if not encrypted_credentials:

517

return None

518

519

# Decrypt credentials

520

decrypted_data = fernet.decrypt(encrypted_credentials.encode())

521

credentials = json.loads(decrypted_data.decode())

522

523

return credentials

524

525

except Exception as e:

526

print(f"Failed to load device credentials: {e}")

527

return None

528

529

def remove_device_credentials(self, username):

530

"""Remove stored device credentials."""

531

cred_name = f"{username}_device_credentials"

532

key_name = f"{username}_device_key"

533

534

try:

535

keyring.delete_password(self.service_name, cred_name)

536

keyring.delete_password(self.service_name, key_name)

537

print("Device credentials removed")

538

except Exception as e:

539

print(f"Failed to remove credentials: {e}")

540

541

# Usage

542

storage = SecureDeviceStorage("MyCognitoApp")

543

544

# Store credentials after device registration

545

device_creds = {

546

'device_key': 'device-key-123',

547

'device_group_key': 'group-key-456',

548

'device_password': 'device-password-789',

549

'device_name': 'My Laptop'

550

}

551

552

storage.store_device_credentials('user@example.com', device_creds)

553

554

# Load credentials for authentication

555

loaded_creds = storage.load_device_credentials('user@example.com')

556

if loaded_creds:

557

print(f"Loaded device: {loaded_creds['device_name']}")

558

```