Authorization problem on backend server with App Store Server API

Hello, I need to access App Store Server API from my production server to check the subscription status of the users.

This is the Java code i'm using, that works perfectly on my computer office, and does not work on the production server and other development machines (401 error code, authorization).

Does anyone have any idea where I'm going wrong? The amazing thing is that it only works on one machine and nowhere else.


	private static final String ISSUER_ID = "68a25a66-32e6-4ad2-8a72-5a60d27f4719";

	private static final String PRIVATE_KEY_FILENAME = "SubscriptionKey_Z7U53CT8QU.p8";

	public static final int CONNECTION_TIMEOUT = 10000;
	
	public static final void main(String[] args) throws Exception {
		String token = prepareJwtToken();
		System.out.println(token);

		String jsonData = fetchUrl(
				"https://api.storekit-sandbox.itunes.apple.com/inApps/v1/subscriptions/1000000849259545", token);

		System.out.println(" * * * * *");
		System.out.println(jsonData);
	}

	public static PrivateKey getPrivateKey(String filename) throws IOException {

		String algorithm = "EC";
		String content = new String(Files.readAllBytes(Paths.get(filename)), StandardCharsets.UTF_8);
		try {
			String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
					.replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");

			KeyFactory kf = KeyFactory.getInstance(algorithm);
			return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException("Java did not support the algorithm:" + algorithm, e);
		} catch (InvalidKeySpecException e) {
			throw new RuntimeException("Invalid key format");
		}
	}

	private static final String prepareJwtToken() throws JSONException, IOException {

		long unixTime = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
		PrivateKey privateKey = getPrivateKey(PRIVATE_KEY_FILENAME);

		Map<String, Object> claims = new HashMap<>();
		claims.put("iss", ISSUER_ID);
		claims.put("iat", unixTime);
		claims.put("exp", (unixTime + (60 * 30)));
		claims.put("aud", "appstoreconnect-v1");
		claims.put("bid", "it.iperdesign.fantaclub");
		Map<String, Object> headers = new HashMap<>();
		headers.put("alg", "ES256");
		headers.put("typ", "JWT");
		headers.put("kid", "Z7U53CT8QU");
		@SuppressWarnings("deprecation")
		String token = Jwts.builder().setHeader(headers).setClaims(claims)
				.signWith(io.jsonwebtoken.SignatureAlgorithm.ES256, privateKey).compact();
		return token;
	}

	private static final String fetchUrl(String urlToFetch, String token) throws IOException {
		URL url = new URL(urlToFetch);
		URLConnection urlCon = url.openConnection();
		urlCon.setRequestProperty("Authorization", "Bearer " + token);
		urlCon.setReadTimeout(CONNECTION_TIMEOUT);
		urlCon.setUseCaches(false);

		InputStream in = null;
		try {
			in = urlCon.getInputStream();
			String jsonData = new String(in.readAllBytes(), StandardCharsets.UTF_8);
			return jsonData;

		} finally {
			if (in != null) {
				in.close();
			}
		}
	}
}

Replies

Thank you for reaching out, reviewing your code nothing jumps out as an obvious misconfiguration. Please file a ticket with Feedback Assistant and post the FB number here, and in the ticket include the output including all returned headers of calling our API and getting a 401, and a copy of this code.