WeatherKit REST API 401 Unauthorized {reason:NOT_ENABLED}

Hello - migrated from darksky to WeatherKit in April of this year. With some difficulty finally got the REST API to work via the following resources: https://developer.apple.com/weatherkit/get-started/ which is horribly inadequate for JWT instructions. So i also used: https://dev.iachieved.it/iachievedit/weatherkit-rest-api/ which was quite helpful. As stated, in April i managed to get this working. About a week ago it stopped working. The response from my calls are 401 Unauthorized in the header and { "reason": "NOT_ENABLED" } in the body. I believe the key i created expired and thus WeatherKit stopped responding. So i tried to re-enable access using the same Apple key and a new JWT signature. That did not seem to work, so i removed the old key and created a new one. Downloaded the p8 file and used openssl on my ubuntu server to create pem and pub files for the jwt token. Still nothing. I have tried almost all combinations of keys and ID #s in the JWT.io console that i can think of. Importantly, nowhere in the official Apple documentation does it say what parameters the key creation and expiry dates can be. Does the key creation date have to match the date the key was created in Apple Developer Console??? What expiry dates are valid???? No idea. I have submitted a code level request, but they punted me to feedback which apparently does nothing. Still no resolution, nor have i been contacted once by an Apple representative. This is what my $200 developer fee gets me?! Unacceptable. If anyone has any idea on how to resolve this issue and/or create valid jwt tokens easier (via PHP preferably), i'm all ears. Thanks, airyt

Post not yet marked as solved Up vote post of airyt Down vote post of airyt
812 views

Replies

I don't have an answer but I'm experiencing the same frustration. I'm trying to use python to generate my JWT then generate a curl command to test in the terminal (because it has verbose messaging).

I created a private key. under "Keys" create a key with the + button. this generates a file AuthKey_{KEY_ID}.p8 where {KEY_ID} is the key_id that was given. I downloaded the p8 file. I converted the p8 file to .pem using openssl pkcs8 -nocrypt -in AuthKey_{KEY_ID}.p8 -out AuthKey_{KEY_ID}.pem I've seen different instructions regarding the creation of the identifier. the documentation says create a ServiceID. an 'influencer' I've tried to follow says to create an App ID identifier. I tried both but have questions: 1) if serviceID do I need to enable "Sign in with Apple". I did not. 2) If AppID, a) which appID Prefix do I choose? I chose the one associated with TeamID, although that was not the default. b) do I tick the box for WeatherKit under the Capabilities or App Services sub-tab? it offers both. I chose both. 3) I created a JWT using python. I have understood that the one 'key' is to get the header to include the APP_ID (the reverse URL). here's what I'm trying but it still fails:

## note remember to update the file path of the .pem file to reflect your username and file location
import jwt
import datetime

TEAM_ID = 'NONYABIZN5'
KEY_ID = '4WHTVRUWNT'
APP_ID = 'com.beispiel.WetterAPI'
file_path = f'/Users/myUser/sandbox/wetterapi/AuthKey_{KEY_ID}.pem'

header = {
  "alg": "ES256",
  "kid": KEY_ID,
  "id": f"{TEAM_ID}.{APP_ID}"
}

current_time = datetime.datetime.utcnow()
expiration_time = current_time + datetime.timedelta(minutes=19)

payload = {
  "iss": TEAM_ID,
  "iat": int(current_time.timestamp()),
  "exp": int(expiration_time.timestamp()),
  "sub": APP_ID
}

with open(file_path, 'r') as file:
  private_key = file.read()

token = jwt.encode(payload, private_key, algorithm='ES256', headers=header)

# Create the curl command
curl_command = f'curl -v -H "Authorization: Bearer {token}" "https://weatherkit.apple.com/api/v1/availability/37.323/122.032?country=US"'

print(curl_command)

that produces a curl command that I can drop into my terminal. the curl returns:

* Connected to weatherkit.apple.com (2600:1408:c400:58::17d5:9e54) port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted http/1.1
* Server certificate:
*  subject: CN=weather-data.apple.com; O=Apple Inc.; ST=California; C=US
*  start date: Jul 25 21:03:10 2023 GMT
*  expire date: Oct 23 21:13:10 2023 GMT
*  subjectAltName: host "weatherkit.apple.com" matched cert's "weatherkit.apple.com"
*  issuer: CN=Apple IST CA 8 - G1; OU=Certification Authority; O=Apple Inc.; C=US
*  SSL certificate verify ok.
* using HTTP/1.1
> GET /api/v1/availability/37.323/122.032?country=US HTTP/1.1
> Host: weatherkit.apple.com
> User-Agent: curl/8.1.2
> Accept: */*
> Authorization: Bearer sdfsfns,dfnanflsandfasdanflknasdlknalsdknlnlnasflnldsfknalasdfknlksandflnsdflnasdflnsaldfknsldakfnlskndflsknadflnsadflnsaldfnaoiw,vm,asfdlkjsdlfklnvlnasdjfsdfadnflsakfndklsfdalknklfsdnlklrewoewu8llnsLSKNlkzxcLKlKNlnskdKVLKSNlknZLKcnLKLKAlkaMLnSDVBisdbdkvbkjvsavskajdbzCXk-2-TasdE-skdfjKJHkjKLlkJLKJlkNLnLKHHiUbKBNhIUHIU
> 
< HTTP/1.1 401 Unauthorized
< Server: Apple
< X-Frame-Options: SAMEORIGIN
< Strict-Transport-Security: max-age=31536000; includeSubdomains
< X-XSS-Protection: 1; mode=block
< Access-Control-Allow-Origin: *
< X-Content-Type-Options: nosniff
< Content-Security-Policy: default-src 'self';
< X-REQUEST-ID: 8e5e48ac-410a-4398-b7e6-8d4fbd0454a4
< Date: Thu, 17 Aug 2023 01:56:37 GMT
< X-Cache: TCP_MISS from a23-202-158-148.deploy.akamaitechnologies.com (AkamaiGHost/11.2.2-50400341) (-)
< Connection: close
< 
* Closing connection 0
{"reason": "NOT_ENABLED"}% 

I've tried this with both "Identifiers" by choosing a suffix to my Reverse URL and using that in one and not using that in the other... I hope that helps more than it confuses. I'd love if someone with knowledge can point me (us) in the right direction...