Я работал над созданием приложения с использованием API-интерфейса разработчика AthenaHealth и пытался протестировать вызов API-интерфейса AthenaHealth с использованием аутентификации JWT в приложении Node.js. Тем не менее, я столкнулся с ошибками, которые я не смог решить. По сути, я следовал методу аутентификации на основе JWT Client Assertion настолько близко, насколько это возможно, со страницы разработчика AthenaHealth, которую можно найти здесь:
.https://docs.athenahealth.com/api/guides/authentication-and-url-locations
На данный момент мне удалось создать JWT Client Assertion со следующим кодом:
// For creating the variables used for the initial token parameters
const privateKey = fs.readFileSync("./thirdprivatekey.key", 'utf8')
const clientId = "*************"
const now = Math.floor(new Date().getTime()/1000)
const expire = new Date((now + 300)*1000)
const claims = {
aud: "https://athena.okta.com/oauth2/aus2hfei6ookPyyCA297/v1/token"
}
// Then creating the token using the njwt library
const jwt = njwt
.create(claims, privateKey, "RS256")
.setHeader("kid", 3)
.setIssuedAt(now)
.setExpiration(expire)
.setIssuer(clientId)
.setSubject(clientId)
.compact()
Пока это не дает ошибок, и я могу создать токен.
Идентификатор клиента подвергся цензуре в целях безопасности, но я использую то же, что и приложение для разработчиков Athena Health. Я также использовал здесь ключи от генератора ключей RS256 (https://mkjwk.org/). А что касается privateKey, я сохраняю его как файл .key в формате pem с -----BEGIN PRIVATE KEY----- -----END PRIVATE KEY----- и имеет длину 64 в ширину.
Но мне не удалось передать этот токен, чтобы запросить второй токен, который будет использоваться для реальных вызовов API. Я проверяю исходный токен, используя метод verify из библиотеки njwt (его можно найти здесь: https://github.com/jwtk/njwt), а затем передаю этот токен в POST- fetch, чтобы получить следующий токен для вызова API AthenaHealth, если токен действителен. Вот код, который я сделал для этого:
njwt.verify(jwt, privateKey, "RS256", function(err,verifiedJwt){
if(err){
console.log(err); // Token has expired, has been tampered with, etc
}else{
console.log(verifiedJwt); // Will contain the header and body
// Creating the body to pass into the POST request
const data = {
grant_type : "client_credentials",
scope : "athena/service/Athenanet.MDP.*",
client_assertion_type : "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
client_assertion : jwt
}
// Calling the AthenaHealth API to get the token to be used for API calls
fetch("https://api.preview.platform.athenahealth.com/oauth2/v1/token", {
method: "POST",
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
//“ Authorization": `Bearer ${jwt}`
},
data : data
})
.then(res => res.json())
.then(resData => console.log(resData))
}
});
}
Когда я преобразовываю ответ в JSON и записываю его в консоль, я получаю «Внутренняя ошибка сервера» как в ответах «ошибка», так и в ответах «detailedMessage». Когда я просто записываю ответ в консоли, не преобразовывая его в JSON, я получаю Promise с надписью «Status: 500» и «statusText: «Unauthorized»».
Примечание о заголовке «Авторизация»: когда я раскомментирую его и передам туда токен, я получаю «Неверный заголовок авторизации» и подробное сообщение «Предоставленный заголовок авторизации имеет неверный формат». Я также пытался использовать «application/json» для Content-Type и все равно получаю те же ошибки.
Мне интересно, использую ли я неправильный метод, пропустил ли шаг или что-то в этом роде. Или, возможно, я что-то делаю неправильно с privateKey и pem или начальным токеном? Означает ли ошибка "заголовок неверный формат", что есть что-то, что не принадлежит заголовку?