or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication-flows.mddevice-code-flow.mdindex.mdlogging-error-handling.mdtoken-caching.md

device-code-flow.mddocs/

0

# Device Code Flow

1

2

Specialized OAuth2 device code flow for applications running on devices without web browsers or with limited input capabilities. This flow is ideal for IoT devices, CLI tools, smart TVs, or other scenarios where traditional web-based authentication is not feasible.

3

4

## How Device Code Flow Works

5

6

1. Application requests a device code and user code from Azure AD

7

2. User is presented with a user code and verification URL

8

3. User navigates to the URL on a separate device and enters the code

9

4. Application polls Azure AD for token using the device code

10

5. Once user completes authentication, Azure AD returns tokens

11

12

## Capabilities

13

14

### Initiate Device Code Flow

15

16

Requests device and user codes from Azure Active Directory to begin the device authentication process.

17

18

```python { .api }

19

def acquire_user_code(self, resource, client_id, language=None):

20

"""

21

Get device code and user code for device flow authentication.

22

23

Parameters:

24

- resource (str): URI identifying the target resource

25

- client_id (str): OAuth2 client ID of the application

26

- language (str, optional): Language code for user messages (e.g., 'en-us')

27

28

Returns:

29

dict: Device code response containing:

30

- userCode (str): Code for user to enter at verification URL

31

- deviceCode (str): Device code for polling token endpoint

32

- verificationUrl (str): URL where user enters the code

33

- expiresIn (int): Seconds until codes expire (typically 900)

34

- interval (int): Recommended polling interval in seconds

35

- message (str): User-friendly instructions

36

"""

37

```

38

39

**Usage Example:**

40

41

```python

42

import adal

43

import time

44

45

context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')

46

47

# Get device code

48

user_code_info = context.acquire_user_code(

49

resource='https://management.azure.com/',

50

client_id='your-client-id'

51

)

52

53

print(f"Please visit {user_code_info['verificationUrl']}")

54

print(f"And enter this code: {user_code_info['userCode']}")

55

print(f"Message: {user_code_info['message']}")

56

```

57

58

### Complete Device Code Authentication

59

60

Polls Azure Active Directory for tokens using the device code after the user has completed authentication.

61

62

```python { .api }

63

def acquire_token_with_device_code(self, resource, user_code_info, client_id):

64

"""

65

Poll for token using device code after user authentication.

66

67

Parameters:

68

- resource (str): URI identifying the target resource

69

- user_code_info (dict): Device code response from acquire_user_code()

70

- client_id (str): OAuth2 client ID of the application

71

72

Returns:

73

dict: Authentication result with access token, refresh token, and metadata

74

75

Raises:

76

AdalError: If user denies consent, code expires, or other authentication errors

77

"""

78

```

79

80

**Usage Example:**

81

82

```python

83

# After displaying user code, poll for token

84

try:

85

token = context.acquire_token_with_device_code(

86

resource='https://management.azure.com/',

87

user_code_info=user_code_info,

88

client_id='your-client-id'

89

)

90

print("Authentication successful!")

91

print(f"Access token: {token['accessToken']}")

92

93

except adal.AdalError as e:

94

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

95

```

96

97

### Cancel Device Code Request

98

99

Cancels an ongoing device code authentication request, useful when the application needs to abort the flow.

100

101

```python { .api }

102

def cancel_request_to_get_token_with_device_code(self, user_code_info):

103

"""

104

Cancel ongoing device code authentication request.

105

106

Parameters:

107

- user_code_info (dict): Device code response from acquire_user_code()

108

109

Returns:

110

None

111

"""

112

```

113

114

**Usage Example:**

115

116

```python

117

# Cancel if user requests abort or timeout occurs

118

context.cancel_request_to_get_token_with_device_code(user_code_info)

119

print("Device authentication cancelled")

120

```

121

122

## Complete Device Code Flow Example

123

124

```python

125

import adal

126

import time

127

import threading

128

129

def device_flow_authentication():

130

authority_url = 'https://login.microsoftonline.com/your-tenant-id'

131

context = adal.AuthenticationContext(authority_url)

132

133

resource = 'https://management.azure.com/'

134

client_id = 'your-client-id'

135

136

try:

137

# Step 1: Get device code

138

print("Initiating device code flow...")

139

user_code_info = context.acquire_user_code(resource, client_id)

140

141

# Step 2: Display instructions to user

142

print(f"\nTo sign in, use a web browser to open the page:")

143

print(f"{user_code_info['verificationUrl']}")

144

print(f"\nAnd enter the code: {user_code_info['userCode']}")

145

print(f"\nMessage: {user_code_info['message']}")

146

print(f"\nWaiting for authentication...")

147

148

# Optional: Set up cancellation after timeout

149

def cancel_after_timeout():

150

time.sleep(user_code_info['expiresIn'])

151

try:

152

context.cancel_request_to_get_token_with_device_code(user_code_info)

153

print("\nDevice code expired, authentication cancelled")

154

except:

155

pass # May already be completed

156

157

timeout_thread = threading.Thread(target=cancel_after_timeout)

158

timeout_thread.daemon = True

159

timeout_thread.start()

160

161

# Step 3: Poll for token

162

token = context.acquire_token_with_device_code(

163

resource, user_code_info, client_id

164

)

165

166

print("\nAuthentication successful!")

167

print(f"User: {token.get('userId', 'Unknown')}")

168

print(f"Token expires: {token.get('expiresOn', 'Unknown')}")

169

170

return token

171

172

except adal.AdalError as e:

173

print(f"\nDevice authentication failed: {e}")

174

return None

175

176

# Run the flow

177

token = device_flow_authentication()

178

```

179

180

## Error Handling

181

182

Device code flow can fail for several reasons:

183

184

- **User cancellation**: User denies consent or closes browser

185

- **Code expiration**: User doesn't complete authentication within time limit

186

- **Invalid client**: Client ID is not configured for device code flow

187

- **Network issues**: Connectivity problems during polling

188

189

```python

190

try:

191

token = context.acquire_token_with_device_code(

192

resource, user_code_info, client_id

193

)

194

except adal.AdalError as e:

195

if "authorization_pending" in str(e):

196

# Still waiting for user - continue polling

197

pass

198

elif "authorization_declined" in str(e):

199

print("User declined authorization")

200

elif "expired_token" in str(e):

201

print("Device code expired")

202

else:

203

print(f"Other error: {e}")

204

```

205

206

## Best Practices

207

208

1. **Display clear instructions**: Show both the URL and code prominently

209

2. **Handle timeouts gracefully**: Codes typically expire in 15 minutes

210

3. **Respect polling intervals**: Use the recommended interval from the response

211

4. **Provide cancellation**: Allow users to abort the flow

212

5. **Cache tokens**: Store refresh tokens for future use to avoid repeated device flows