Async Authentication

이 μ˜ˆμ‹œλŠ” htmxλ₯Ό μ‚¬μš©ν•˜μ—¬ 비동기 인증 토큰 흐름을 κ΅¬ν˜„ν•˜λŠ” 방법을 λ³΄μ—¬μ€λ‹ˆλ‹€.

μ—¬κΈ°μ„œ μ‚¬μš©ν•  κΈ°μˆ μ€ htmx:confirm 이벀트λ₯Ό μ‚¬μš©ν•˜μ—¬ μš”μ²­μ„ μ§€μ—°μ‹œν‚¬ 수 μžˆλ‹€λŠ” 점을 ν™œμš©ν•©λ‹ˆλ‹€.

μš°μ„ , 인증 토큰이 검색될 λ•ŒκΉŒμ§€ μš”μ²­μ„ 보내지 μ•Šμ•„μ•Ό ν•˜λŠ” λ²„νŠΌμ„ μƒμ„±ν•©λ‹ˆλ‹€:

  <button hx-post="/example" hx-target="next output">
    An htmx-Powered button
  </button>
  <output>
    --
  </output>

λ‹€μŒμœΌλ‘œ, auth ν”„λ‘œλ―ΈμŠ€(λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ λ°˜ν™˜λœ)λ₯Ό μ²˜λ¦¬ν•˜κΈ° μœ„ν•œ 슀크립트λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€:

<script>
  // authλŠ” 인증 μ‹œμŠ€ν…œμ—μ„œ λ°˜ν™˜λœ ν”„λ‘œλ―ΈμŠ€μž…λ‹ˆλ‹€.

  // 인증 토큰을 λŒ€κΈ°ν•˜κ³ , 이λ₯Ό 어디에 μ €μž₯ν•©λ‹ˆλ‹€.
  let authToken = null;
  auth.then((token) => {
    authToken = token
  })
  
  // 인증 토큰에 따라 htmx μš”μ²­μ„ μ œμ–΄ν•©λ‹ˆλ‹€.
  htmx.on("htmx:confirm", (e)=> {
    // 인증 토큰이 없을 경우
    if(authToken == null) {
      // μ •κ·œ μš”μ²­μ΄ λ°œν–‰λ˜μ§€ μ•Šλ„λ‘ λ§‰μŠ΅λ‹ˆλ‹€.
      e.preventDefault() 
      // 인증 ν”„λ‘œλ―ΈμŠ€κ°€ ν•΄κ²°λœ ν›„μ—λ§Œ μš”μ²­μ„ λ°œν–‰ν•©λ‹ˆλ‹€.
      auth.then(() => e.detail.issueRequest()) 
    }
  })

  // μš”μ²­μ— 인증 토큰을 ν—€λ”λ‘œ μΆ”κ°€ν•©λ‹ˆλ‹€.
  htmx.on("htmx:configRequest", (e)=> {
    e.detail.headers["AUTH"] = authToken
  })
</script>

μ—¬κΈ°μ—μ„œλŠ” κΈ€λ‘œλ²Œ λ³€μˆ˜λ₯Ό μ‚¬μš©ν–ˆμ§€λ§Œ, localStorageλ‚˜ λ‹€λ₯Έ μ„ ν˜Έν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ„ μ‚¬μš©ν•˜μ—¬ 인증 토큰을 htmx:configRequest μ΄λ²€νŠΈμ— 전달할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

이 μ½”λ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ auth ν”„λ‘œλ―ΈμŠ€κ°€ 해결될 λ•ŒκΉŒμ§€ htmxκ°€ μš”μ²­μ„ λ°œν–‰ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.