Handle Oauth Process in an Electron App

學習Blog
5 min readJan 7, 2024

--

開放授權(OAuth)是一個開放標準,允許使用者讓第三方應用訪問該使用者在某一網站上儲存的私密的資源(如相片,影片,聯絡人列表),而無需將使用者名稱和密碼提供給第三方應用。 ( Wiki )

這邊紀錄 Electron App 要怎麼使用 OAuth 取得第三方服務。

OAuth 流程

https://www.hesabit.com/docs/api/oauth2

OAuth 流程網路上已經有很多詳盡資料,這邊就不做詳述;簡單來說步驟是

  1. 根據需要的權限 ( Scopes ) 需求進入第三方提供的認證網址
  2. 使用者登入
  3. 第三方驗證後,提供相關權限

方法一

用 Electron 開啟第三方畫面,並用 onBeforeRequest 攔截資料,取得 token 後,存到記憶體或用 keytar 存到電腦帳號中

const userLogin = () => {
const {
session: { webRequest }
} = authWindow.webContents

const filter: WebRequestFilter = {
urls: ['APP_REDIRECT_URL']
}

const handleRedirectUrl = (url: string) => {
/** 分析 Redirect Url,發出 api 請求 token、refresh token */
}

webRequest.onBeforeRequest(filter, handleRedirectUrl)

authWindow.loadURL(Authentication_URL)
}

/** App 執行當下驗證是否已經有 token,沒有則進入驗證流程 */
app.on('ready', async () => {
try {
await AuthService.refreshTokens()

MainProcess.init()
} catch (error) {
userLogin()
}
})

但這個用法有兩個問題

  1. Electron 提供的瀏覽器不會更新版本,登入第三方可能會遭拒
  2. 不夠安全

方法二

使用系統本身的瀏覽器,並用 nodejs http module 建立簡易 server 處理 redirect url

/** render process 載入畫面完成後,驗證 token */
ipcMain.on('on render process finish', async () => {
try {
await AuthService.refreshTokens()
} catch (error) {
MainProcess.setAuthReadyStatus(false)
}
})

/** AuthReadyStatus 為 false 時,顯示登入按鈕 */
ipcMain.on('open:auth', (event, args) => {
login()
})

/** 建立 server,攔截 redirect url 取得 token */
function setServer() {
return new Promise<void>((res, rej) => {
AuthProcess.server = http.createServer(async (request, response) => {
await handleRedirectUrl(
`http://${request.headers.host}${request.url}`
)

response.statusCode = 200
response.setHeader('Content-Type', 'text/html')
response.end(`<h1>Login success.</h1>`)

MainProcess.setAuthReadyStatus(true)

AuthProcess.server.close()
AuthProcess.server = null
})

AuthProcess.server.listen(3000, res)
})
}

/** 用 shell.openExternal 開啟系統瀏覽器 */
function login() {
await setServer()

await shell.openExternal(AuthService.authenticationURL())
}

app.on('ready', MainProcess.init)

這邊可能需要去檢查目前 server port 是否有被占用,另外也可以用 app.setAsDefaultProtocolClient 自動導向 Electron app 本身

--

--

學習Blog
學習Blog

No responses yet