Auth0 SPA TypeError: Невозможно прочитать свойство 'idTokenPayload' из неопределенного - PullRequest
0 голосов
/ 02 ноября 2019

Я получаю сообщение об ошибке в моем приложении Gatsby + Auth0 при попытке войти в систему. Вот ошибка:

TypeError: Cannot read property 'idTokenPayload' of undefined
(anonymous function)
src/utils/auth.js:1
> 1 | import auth0 from "auth0-js"
  2 | import { navigate } from "gatsby"
  3 | 
  4 | const isBrowser = typeof window !== "undefined"

Когда я вхожу в свое приложение, оно работает в первый раз, и я могувижу, что authResult записывает в консоль правильные значения, но в тот момент, когда я нажимаю на любые маршруты или обновляю страницу, она возвращает эту ошибкуДо сегодняшнего утра я работал нормально, я не изменил ничего, кроме некоторых стилей CSS.

Вот мой файл auth.js:

import auth0 from "auth0-js"
import { navigate } from "gatsby"

const isBrowser = typeof window !== "undefined"

const auth = isBrowser
  ? new auth0.WebAuth({
      domain: process.env.AUTH0_DOMAIN,
      clientID: process.env.AUTH0_CLIENTID,
      redirectUri: process.env.AUTH0_CALLBACK,
      responseType: "token id_token",
      scope: "openid profile email",
    })
  : {}

const tokens = {
  accessToken: false,
  idToken: false,
  expiresAt: false,
}

let user = {}

export const isAuthenticated = () => {
  if (!isBrowser) {
    return
  }

  return localStorage.getItem("isLoggedIn") === "true"
}

export const login = () => {
  if (!isBrowser) {
    return
  }

  auth.authorize()
}

const setSession = (cb = () => {}) => (err, authResult) => {

  console.log(authResult);

  localStorage.setItem("userAuthID", authResult.idTokenPayload.sub)
  localStorage.setItem("userIdToken", 'Bearer '+authResult.idToken)
  if (err) {
    navigate("/")
    cb()
    return
  }

  if (authResult && authResult.accessToken && authResult.idToken) {
    let expiresAt = authResult.expiresIn * 1000 + new Date().getTime()
    tokens.accessToken = authResult.accessToken
    tokens.idToken = authResult.idToken
    tokens.expiresAt = expiresAt
    user = authResult.idTokenPayload
    localStorage.setItem("isLoggedIn", true)
    navigate("/account")
    cb()
  }

}

export const silentAuth = callback => {
  if (!isAuthenticated()) return callback()
  auth.checkSession({}, setSession(callback))
}

export const handleAuthentication = () => {
  if (!isBrowser) {
    return
  }

  auth.parseHash(setSession())
}

export const getProfile = () => {
  return user
}

export const logout = () => {
  localStorage.setItem("isLoggedIn", false)
  localStorage.removeItem("userIdToken");
  auth.logout()
}

А вот мой callback.jsfile:

import React, { Component } from 'react'
import { handleAuthentication } from "../utils/auth"
import { navigate } from 'gatsby';

export default class callback extends Component {

  componentDidMount() {
    handleAuthentication();
    setTimeout(() => {
      navigate('/account')
    }, 1500);
  }

  render() {
    return (
      <div>
        <div className="hero is-white is-fullheight">
          <div className="hero-body">
            <div className="container">
              <h1 className="title is-1 is-spaced has-text-centered logo-text">Fottom</h1>
            </div>
          </div>
        </div>
      </div>
    )
  }
}

Может кто-нибудь помочь мне найти то, чего здесь не хватает? Спасибо!

Ответы [ 2 ]

0 голосов
/ 04 ноября 2019

Я согласен с @mhSangar в том, что вы, вероятно, должны пытаться получить доступ только к полезной нагрузке ПОСЛЕ того, чтобы убедиться, что это не null.

Но я думаю, что есть еще один уровень проблемы, с которой вы столкнулись. Вы упомянули, что все работает нормально, пока вы не обновите, что я предполагаю, когда попытка обновления токена. Я предполагаю, что проблема заключается в методе checkSession.

В настоящее время он вызывается так:

auth.checkSession({}, setSession(callback))

Вы должны передать конфигурацию какпервый аргумент этого метода (не просто пустой объект). Когда я вызываю его в своем приложении, я передаю следующие аргументы:

{
  audience,
  callbackURL,
  clientID,
  domain
}

Попробуйте передать эти аргументы auth.checkSession и посмотрите, исправляет ли это.

то есть

export const silentAuth = callback => {
  if (!isAuthenticated()) return callback()
  auth.checkSession(
    {
      domain: process.env.AUTH0_DOMAIN,
      clientID: process.env.AUTH0_CLIENTID,
      redirectUri: process.env.AUTH0_CALLBACK,
      audience: YOUR_AUDIENCE (looks like AUTH0_DOMAIN/api/v2/)
    },
    setSession(callback)
  )
}
0 голосов
/ 03 ноября 2019

Ваша проблема здесь в том, что вы пытаетесь получить доступ к свойству idTokenPayload из authResult, не проверяя ранее, является ли authResult нулевым. В вашей функции setSession(), в случае ошибки, вы получаете доступ к authResult. Вы должны устанавливать элементы localStorage только после успешного входа в систему.

Попробуйте этот код:

const setSession = (cb = () => {}) => (err, authResult) => {

  console.log(authResult);

  if (err) {
    navigate("/")
    cb()
    return
  }

  if (authResult && authResult.accessToken && authResult.idToken) {

    localStorage.setItem("userAuthID", authResult.idTokenPayload.sub) // moved after error control
    localStorage.setItem("userIdToken", 'Bearer '+authResult.idToken) // moved after error control

    let expiresAt = authResult.expiresIn * 1000 + new Date().getTime()
    tokens.accessToken = authResult.accessToken
    tokens.idToken = authResult.idToken
    tokens.expiresAt = expiresAt
    user = authResult.idTokenPayload
    localStorage.setItem("isLoggedIn", true)
    navigate("/account")
    cb()
  }

}
...