This flow lets you try out the Auth0 Device Flow using a CLI.
Update the parameters AUTH0_DOMAIN, CLIENT_ID, and AUDIENCE at the top of the file first.
Run node index.js to try the flow.
| const { exec } = require('child_process'); | |
| const readline = require('readline'); | |
| const AUTH0_DOMAIN = 'TENANT_DOMAIN'; | |
| const CLIENT_ID = 'CLIENT_ID'; | |
| const AUDIENCE = 'AUDIENCE'; | |
| const DEVICE_CODE_URL = `https://${AUTH0_DOMAIN}/oauth/device/code`; | |
| const TOKEN_URL = `https://${AUTH0_DOMAIN}/oauth/token`; | |
| const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); | |
| async function pollForToken(deviceCode, intervalSeconds) { | |
| const body = { | |
| grant_type: 'urn:ietf:params:oauth:grant-type:device_code', | |
| device_code: deviceCode, | |
| client_id: CLIENT_ID, | |
| }; | |
| let interval = Number(intervalSeconds) || 5; | |
| while (true) { | |
| // wait interval seconds before each poll | |
| await sleep(interval * 1000); | |
| let response; | |
| let data; | |
| try { | |
| console.log(`Polling token endpoint (interval ${interval} seconds)...`); | |
| response = await fetch(TOKEN_URL, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(body), | |
| }); | |
| data = await response.json(); | |
| } catch (err) { | |
| throw new Error('Network error while polling token endpoint: ' + err.message); | |
| } | |
| if (response.ok) { | |
| // Success — return token response | |
| return data; | |
| } | |
| // Not OK — handle known device flow errors | |
| const errCode = data && data.error; | |
| if (errCode === 'authorization_pending') { | |
| console.log("Authorization is pending."); | |
| // keep polling | |
| continue; | |
| } | |
| if (errCode === 'access_denied') { | |
| throw new Error('Access denied by user: ' + (data.error_description || '')); | |
| } | |
| if (errCode === 'slow_down') { | |
| // increase interval per spec | |
| interval += 5; | |
| continue; | |
| } | |
| // Unknown error — throw | |
| throw new Error('Token endpoint error: ' + JSON.stringify(data)); | |
| } | |
| } | |
| const getDeviceCode = async () => { | |
| console.log(`Sending request to: ${DEVICE_CODE_URL}`); | |
| const body = { | |
| client_id: CLIENT_ID, | |
| scope: 'openid profile email', | |
| audience: AUDIENCE, | |
| }; | |
| try { | |
| const response = await fetch(DEVICE_CODE_URL, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(body), | |
| }); | |
| const responseData = await response.json(); | |
| if (!response.ok) { | |
| const errorMessage = responseData.error_description || `HTTP error! Status: ${response.status}`; | |
| throw new Error(errorMessage); | |
| } | |
| return responseData; | |
| } catch (error) { | |
| console.error('An error occurred during the fetch operation:', error); | |
| throw error; | |
| } | |
| } | |
| async function main() { | |
| try { | |
| const deviceCodeResponse = await getDeviceCode(); | |
| console.log('\nReceived response from Auth0:'); | |
| console.log(JSON.stringify(deviceCodeResponse, null, 2)); | |
| const verificationUrl = deviceCodeResponse.verification_uri_complete; | |
| if (!verificationUrl) { | |
| console.warn('\nERROR: No verification URL found in the response.'); | |
| process.exit(1); | |
| } | |
| const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); | |
| console.log(`\nPress Enter to open the verification URL in your browser:\n${verificationUrl}`); | |
| // wait for user to press Enter | |
| const questionAsync = (query = '') => new Promise((resolve) => rl.question(query, resolve)); | |
| await questionAsync(''); | |
| console.log('Opening browser...'); | |
| exec('open ' + verificationUrl, (err) => { | |
| if (err) { | |
| console.error('Failed to open browser:', err); | |
| } else { | |
| console.log('Browser opened. Follow the instructions to complete sign-in.'); | |
| } | |
| }); | |
| // Start polling for tokens | |
| const tokens = await pollForToken(deviceCodeResponse.device_code, deviceCodeResponse.interval); | |
| console.log('\nToken response received:'); | |
| console.log(JSON.stringify(tokens, null, 2)); | |
| } catch (error) { | |
| console.error('\nScript finished with an error.'); | |
| console.error('Error details:', error); | |
| process.exit(1); | |
| } | |
| } | |
| main(); |