Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow getting all tokens #77

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/MicrosoftAuthFlow.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ class MicrosoftAuthFlow {
}
}

async getMsTokens() {
const ret = await this.msa.fullAuthDeviceCode((response) => {
if (this.codeCallback) return this.codeCallback(response)
console.info('[msa] First time signing in. Please authenticate now:')
console.info(response.message)
})
if (ret.account) {
console.info(`[msa] Signed in as ${ret.account.username}`)
} else { // We don't get extra account data here per scope
console.info('[msa] Signed in with Microsoft')
}
debug('[msa] got auth result', ret)
return ret
}
async getMsaToken () {
if (await this.msa.verifyTokens()) {
debug('[msa] Using existing tokens')
Expand Down
74 changes: 74 additions & 0 deletions src/TokenManagers/LiveTokenManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,81 @@ class LiveTokenManager {
}
})
}
async fullAuthDeviceCode (deviceCodeCallback) {
const acquireTime = Date.now()
const codeRequest = {
method: 'post',
body: new URLSearchParams({ scope: this.scopes, client_id: this.clientId, response_type: 'device_code' }).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
credentials: 'include' // This cookie handler does not work on node-fetch ...
}

debug('Requesting live device token', codeRequest)

const cookies = []

const res = await fetch(Endpoints.LiveDeviceCodeRequest, codeRequest)
.then(res => {
if (res.status !== 200) {
res.text().then(console.warn)
throw Error('Failed to request live.com device code')
}
for (const cookie of Object.values(res.headers.raw()['set-cookie'])) {
const [keyval] = cookie.split(';')
cookies.push(keyval)
}
return res
})
.then(checkStatus).then(resp => {
resp.message = `To sign in, use a web browser to open the page ${resp.verification_uri} and enter the code ${resp.user_code} to authenticate.`
deviceCodeCallback(resp)
return resp
})
const expireTime = acquireTime + (res.expires_in * 1000) - 100 /* for safety */

this.polling = true
while (this.polling && expireTime > Date.now()) {
await new Promise(resolve => setTimeout(resolve, res.interval * 1000))
try {
const verifi = {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Cookie: cookies.join('; ')
},
body: new URLSearchParams({
client_id: this.clientId,
device_code: res.device_code,
grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
}).toString()
}

const token = await fetch(Endpoints.LiveTokenRequest + '?client_id=' + this.clientId, verifi)
.then(res => res.json()).then(res => {
if (res.error) {
if (res.error === 'authorization_pending') {
debug('[live] Still waiting:', res.error_description)
} else {
throw Error(`Failed to acquire authorization code from device token (${res.error}) - ${res.error_description}`)
}
} else {
return res
}
})
if (!token) continue
this.updateCache(token)
this.polling = false
return token
} catch (e) {
console.debug(e)
}
}
this.polling = false
throw Error('Authentication failed, timed out')
}
}
async authDeviceCode (deviceCodeCallback) {
const acquireTime = Date.now()
const codeRequest = {
Expand Down
Loading