I'm stumped. I had everything working Sunday night, pulling weather data from my dev and staging environments. Went to sleep, and now I can't get data in my dev or staging environments. The response received is 401 Unauthorized, { reason: "NOT_ENABLED" }. After attempting several variations with no success, I decided to start over: remake the AppID, ServiceID, and Key (I believe the AppID isn't required).
Here is my current code:
import { sign } from "jsonwebtoken"
import { readFileSync } from "fs"
const generateJWT = async () => {
const secret = readFileSync("./AuthKey_**********.p8")
const signedToken = await signToken(secret)
console.log("Signed Token = ", signedToken) /* Logs token correctly, but the logged token doesn't work in dev or in Postman requests */
return signedToken
}
const signToken = (secret: Buffer) => {
return new Promise((resolve, reject) => {
sign(
{
sub: [ServicesID-Identifier],
},
secret,
{
jwtid: [TeamID.ServicesID-Identifier],
issuer: [TeamID],
expiresIn: "1h",
keyid: [KeyID],
algorithm: "ES256",
header: {
id: [TeamID.ServiceID-Identifier],
},
},
function (error, token) {
error ? reject(error) : resolve(token)
}
)
})
}
export default generateJWT
- All bracketed information is the respective string value.
Fetch code, slightly abbreviated:
const getLocationWeather = async (location) => {
const token = await generateJWT()
const fetchURL = `https://weatherkit.apple.com/api/v1/weather/en-US/${location.lat}/${location.lon}?dataSets=forecastHourly`
const res = await fetch(fetchUrl, {
headers: {
Authorization: `Bearer ${token}`
}
})
console.log("res = ", res.status) /* logs 401 */
const data = await res.json()
console.log("data = ", data) /* logs { reason: "NOT_ENABLED"}
}
Hitting the /availability end-point using Postman and the token's logged above results in the same 401 / NOT_ENABLED.
Outstanding questions requiring confirmation/clarification:
- Is ServiceID the correct ID to use, and NOT AppID?
- Since this implementation uses 'jsonwebtoken' library, there is no need to convert the .p8 private key into .pem, correct?
- I'm new to working with json web tokens. Using jwt.io to debug the generated tokens, I'm uncertain as to what to use for the Public Key box under "verify signature" once ES256 is selected from the drop-down for "Algorithm." This may be the key to troubleshooting why my tokens are failing to authenticate.
Future considerations:
Reading from .p8 is the simplest way to confirm everything is working. Once this is working again, I would like to convert the .p8 private key into an environment variable. This was working in dev/staging by converting the private key into a string, then reading the string as a buffer into the jsonwebtoken.sign() secret value. I'm wondering if this has any implications for why it worked temporarily, but now doesn't.