use TwitchAuth

This commit is contained in:
2025-01-26 11:47:43 +00:00
parent 0d278e19ad
commit 37c8573832
+28 -116
View File
@@ -1,150 +1,62 @@
/** @param {Response} response */ import * as TwitchAuth from './TwitchAuth.mjs'
async function validateResponse(response){ /** @type {import('./TwitchAuth.mjs').TwitchToken} */
if(!response.ok){ let token=null;
throw new Error(response.status+' '+response.url+' '+await response.text())
}
return response
}
export function request_auth(client_id,scope,redirect_uri=location.origin+location.pathname){ export function request_auth(client_id,scope,redirect_uri=location.origin+location.pathname){
const url=new URL('https://id.twitch.tv/oauth2/authorize') return TwitchAuth.requestAuthCode(client_id,scope.split(' '))
url.search=new URLSearchParams({
client_id:client_id,
response_type:'code',
scope:scope
})
const dialog=document.createElement('dialog')
dialog.innerHTML='Redirecting you to Twitch for authorization<br>'
dialog.innerHTML+='If you see this multiple times, please report it as a bug<br>'
const okButton=document.createElement('button')
okButton.innerHTML='OK'
okButton.onclick=()=>location.assign(url.href+'&redirect_uri='+redirect_uri)
dialog.appendChild(okButton)
const cancelButton=document.createElement('button')
cancelButton.innerHTML='Cancel'
cancelButton.onclick=()=>dialog.close()
dialog.appendChild(cancelButton)
document.body.appendChild(dialog)
dialog.showModal()
//if(window.confirm((document.title||location.origin+location.pathname)+' redirecting you to twitch for authorization')){
// location.assign(url.href+'&redirect_uri='+redirect_uri)
//}
} }
export function get_url_params(){ export function get_url_params(){
return Object.fromEntries(new URLSearchParams(location.search)) return Object.fromEntries(new URLSearchParams(location.search))
} }
export function fetch_tokens(client_id,code,redirect_uri=location.origin+location.path){ export async function fetch_tokens(client_id,code,redirect_uri=location.origin+location.path){
const url=new URL('/oauth2/token',import.meta.url) client_id=client_id
const body=new URLSearchParams({ token=await TwitchAuth.exchangeCode(client_id,code)
client_id:client_id, token.client_id=client_id
code:code, return token
grant_type:'authorization_code',
redirect_uri:redirect_uri
}).toString()
return fetch(url.href,{
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:body
})
.then(validateResponse)
.then(response=>response.json())
} }
export function get_headers(tokens){ export function get_headers(tokens){
return { return {
'Authorization':'Bearer '+tokens.access_token, 'Authorization':'Bearer '+token.access_token,
'Client-ID':tokens.client_id 'Client-ID':token.client_id
} }
} }
export function validate_tokens(tokens){ export async function validate_tokens(tokens){
const url=new URL('https://id.twitch.tv/oauth2/validate')//,import.meta.url) const validation=await TwitchAuth.validateToken(tokens.auth_token)
return fetch(url,{headers:{ Object.assign(tokens,validation)
'Authorization':'OAuth '+tokens.access_token tokens.scopes=validation.scope
}}).then(validateResponse) token=tokens
.then(response=>response.json()) return token
.then(validation=>{
if('message' in validation){
throw new Error(validation.message)
}
Object.assign(tokens,validation)
delete tokens.scope
return tokens
})
} }
export function set_local_tokens(client_id,tokens){ export function set_local_tokens(client_id,tokens){
localStorage.setItem(client_id,JSON.stringify(tokens)) token=tokens
return tokens return token
} }
export function get_local_tokens(client_id){ export function get_local_tokens(client_id){
return JSON.parse(localStorage.getItem(client_id)) return token
} }
export function refresh_tokens(client_id,refresh_token){ export async function refresh_tokens(client_id,refresh_token){
const url=new URL('/oauth2/token',import.meta.url) token=await TwitchAuth.refreshToken(client_id,refresh_token)
const body=new URLSearchParams({ return token
client_id:client_id,
grant_type:'refresh_token',
refresh_token:refresh_token
}).toString()
return fetch(url.href,{
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:body
})
.then(validateResponse)
.then(response=>response.json())
} }
export function set_refresh_timeout(client_id,tokens){ export function set_refresh_timeout(client_id,tokens){
return setTimeout(()=>{ return setTimeout(()=>{
get_tokens(client_id) TwitchAuth.refreshToken(client_id,tokens.refresh_token)
.then(new_tokens=>Object.assign(tokens,new_tokens)) .then(new_tokens=>Object.assign(tokens,new_tokens))
},tokens.expires_in*1000) },tokens.expires_in*999)
} }
export async function get_tokens(client_id,scope=null,redirect_uri=location.origin+location.pathname,auth_return=false){ export async function get_tokens(client_id,scope=null,redirect_uri=location.origin+location.pathname,auth_return=false){
let tokens=get_local_tokens(client_id)||get_url_params() token=await TwitchAuth.getUserToken(client_id,scope.split(' ')).then(validate_tokens)
if('code' in tokens){ set_refresh_timeout(client_id,token)
tokens=await fetch_tokens(client_id,tokens.code,redirect_uri) return token
.catch((error)=>console.warn(error))
}
if(!tokens){
tokens={refresh_token:undefined}
}
return refresh_tokens(client_id,tokens.refresh_token)
.then(validate_tokens)
.then(tokens=>{
tokens.auth_headers=get_headers(tokens)
set_refresh_timeout(client_id,tokens)
return set_local_tokens(client_id,tokens)
})
.catch(async (error)=>{
if(error.message==="Failed to fetch"){
await new Promise(function(resolve,reject){
setTimeout(resolve,1000)
})
return get_tokens(client_id,scope,redirect_uri,auth_return)
}
if(scope){
request_auth(client_id,scope,redirect_uri)
}else{
const dialog=document.createElement('dialog')
dialog.innerHTML=(document.title||location.origin+location.pathname)+' has been logged out of your twitch account<br>'
const okButton=document.createElement('button')
okButton.innerHTML='OK'
okButton.onclick=()=>dialog.close()
dialog.appendChild(okButton)
document.body.appendChild(dialog)
dialog.showModal()
localStorage.clear(client_id)
}
throw error
})
} }
export default get_tokens export default get_tokens