Skip to content

Commit

Permalink
Merge pull request #1 from AzimoLabs/master
Browse files Browse the repository at this point in the history
Update fork
  • Loading branch information
shaggy8871 committed Jun 29, 2021
2 parents af2ddd1 + dc37aaa commit 435ed75
Show file tree
Hide file tree
Showing 34 changed files with 332 additions and 538 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.3'
php-version: '8.0'
tools: composer:v2

- name: Validate composer.json and composer.lock
Expand Down
86 changes: 59 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
# Sign-in with Apple SDK

[![Latest Version](https://img.shields.io/github/v/release/AzimoLabs/apple-sign-in-php-sdk.svg?style=flat-square)](https://github.com/AzimoLabs/apple-sign-in-php-sdk/releases)
[![Build Status](https://img.shields.io/github/workflow/status/AzimoLabs/apple-sign-in-php-sdk/CI?label=ci%20build&style=flat-square)](https://github.com/AzimoLabs/apple-sign-in-php-sdk/actions?query=workflow%3ACI)

## Installation

Recommended and easiest way to installing library is through [Composer](https://getcomposer.org/).

`composer require azimolabs/apple-sign-in-php-sdk`

## Requirements

* PHP 7.1+
* OpenSSL Extension

## PHP support
|PHP version|Library version|
|---|---|
|`5.x`|`NOT SUPPORTED`|
| `> 7.0 <= 7.3`| `1.4.x` |
| `> 7.4 < 8.0`| `1.5.x` |
| `> 8.0 & ^7.4`| `2.0.x` |

## How it works
This description assumes that you already have generated [identityToken](https://developer.apple.com/documentation/authenticationservices/asauthorizationsinglesignoncredential/3153080-identitytoken).
Remember that token is valid ONLY for 10 minutes.

The first step to verify the identity token is to generate a public key. To generate public key `exponent` and `modulus` values are required.
Both information are exposed in [Apple API endpoint](https://appleid.apple.com/auth/keys). Those values differ depending on the algorithm.
This description assumes that you already have
generated [identityToken](https://developer.apple.com/documentation/authenticationservices/asauthorizationsinglesignoncredential/3153080-identitytoken)
. Remember that token is valid ONLY for 10 minutes.

The first step to verify the identity token is to generate a public key. To generate public key `exponent` and `modulus`
values are required. Both information are exposed in [Apple API endpoint](https://appleid.apple.com/auth/keys). Those
values differ depending on the algorithm.

The second step is verification if provided `identityToken` is valid against generated public key. If so we are sure that `identityToken` wasn't malformed.
The second step is verification if provided `identityToken` is valid against generated public key. If so we are sure
that `identityToken` wasn't malformed.

The third step is validation if token is not expired. Additionally it is worth to check `issuer` and `audience`, examples are shown below.
The third step is validation if token is not expired. Additionally it is worth to check `issuer` and `audience`,
examples are shown below.

## Basic usage

Once you have cloned repository, make sure that composer dependencies are installed running `composer install -o`.

```php
Expand All @@ -31,29 +48,36 @@ $validationData->setIssuer('https://appleid.apple.com');
$validationData->setAudience('com.azimo');

$appleJwtFetchingService = new Auth\Service\AppleJwtFetchingService(
new Auth\Jwt\JwtParser(new Parser()),
new Auth\Jwt\JwtVerifier(
new Api\AppleApiClient(
new GuzzleHttp\Client(
new Auth\Jwt\JwtParser(new \Lcobucci\JWT\Token\Parser(new \Lcobucci\JWT\Encoding\JoseEncoder())),
new Auth\Jwt\JwtVerifier(
new Api\AppleApiClient(
new GuzzleHttp\Client(
[
'base_uri' => 'https://appleid.apple.com',
'timeout' => 5,
'connect_timeout' => 5,
]
),
new Api\Factory\ResponseFactory()
),
new \Lcobucci\JWT\Validation\Validator(),
new \Lcobucci\JWT\Signer\Rsa\Sha256()
),
new Auth\Jwt\JwtValidator(
new \Lcobucci\JWT\Validation\Validator(),
[
'base_uri' => 'https://appleid.apple.com',
'timeout' => 5,
'connect_timeout' => 5,
new \Lcobucci\JWT\Validation\Constraint\IssuedBy('https://appleid.apple.com'),
new \Lcobucci\JWT\Validation\Constraint\PermittedFor('com.c.azimo.stage'),
]
),
new Api\Factory\ResponseFactory()
),
new RSA(),
new Sha256()
),
new Auth\Jwt\JwtValidator($validationData),
new Auth\Factory\AppleJwtStructFactory()
);
new Auth\Factory\AppleJwtStructFactory()
);

$appleJwtFetchingService->getJwtPayload('your.identity.token');
```

If you don't want to copy-paste above code you can paste freshly generated `identityToken` in `tests/E2e/Auth/AppleJwtFetchingServiceTest.php:53`
If you don't want to copy-paste above code you can paste freshly generated `identityToken`
in `tests/E2e/Auth/AppleJwtFetchingServiceTest.php:53`
and run tests with simple command `php vendor/bin/phpunit tests/E2e`.

```shell script
Expand All @@ -70,16 +94,24 @@ OK (1 test, 1 assertion)
```

## Todo

It is welcome to open a pull request with a fix of any issue:

- [ ] Upgrade `lcobucci/jwt` to version `4.x`. Reported in: [Implicit conversion of keys from strings is deprecated. #2](https://github.com/AzimoLabs/apple-sign-in-php-sdk/issues/2)
- [x] Make library compatible with PHP `7.4.3`. Reported in [Uncaught JsonException: Malformed UTF-8 characters](https://github.com/AzimoLabs/apple-sign-in-php-sdk/issues/4)
- [ ] Make library compatible with PHP `8.0.0`
- [x] Upgrade `phpseclib/phpseclib` to version `3.0.7`
- [x] Upgrade `lcobucci/jwt` to version `4.x`. Reported
in: [Implicit conversion of keys from strings is deprecated. #2](https://github.com/AzimoLabs/apple-sign-in-php-sdk/issues/2)
- [x] Make library compatible with PHP `7.4.3`. Reported
in [Uncaught JsonException: Malformed UTF-8 characters](https://github.com/AzimoLabs/apple-sign-in-php-sdk/issues/4)
- [x] Make library compatible with PHP `8.0.0`

## Miscellaneous

* [JSON web token](https://jwt.io/)
* [Sign in with Apple overwiew](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple)
* [How backend token verification works](https://sarunw.com/posts/sign-in-with-apple-3/)

# Towards financial services available to all
We’re working throughout the company to create faster, cheaper, and more available financial services all over the world, and here are some of the techniques that we’re utilizing. There’s still a long way ahead of us, and if you’d like to be part of that journey, check out our [careers page](https://bit.ly/3vajnu6).

We’re working throughout the company to create faster, cheaper, and more available financial services all over the
world, and here are some of the techniques that we’re utilizing. There’s still a long way ahead of us, and if you’d like
to be part of that journey, check out our [careers page](https://bit.ly/3vajnu6).
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
},
"minimum-stability": "stable",
"require": {
"php": "^7.1",
"php": "^7.4 || ^8.0",
"ext-mbstring": "*",
"ext-openssl": "*",
"phpseclib/phpseclib": "^2.0",
"lcobucci/jwt": "3.3.3",
"phpseclib/phpseclib": "^3.0",
"lcobucci/jwt": "^4.0",
"guzzlehttp/guzzle": "^6.0|^7.0"
},
"require-dev": {
Expand Down
18 changes: 7 additions & 11 deletions src/Api/AppleApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@
use Azimo\Apple\Api\Exception\PublicKeyFetchingFailedException;
use Azimo\Apple\Api\Factory\ResponseFactory;
use GuzzleHttp;
use GuzzleHttp\Utils;
use InvalidArgumentException;

class AppleApiClient
final class AppleApiClient implements AppleApiClientInterface
{
/**
* @var GuzzleHttp\ClientInterface
*/
private $httpClient;
private GuzzleHttp\ClientInterface $httpClient;

/**
* @var ResponseFactory
*/
private $responseFactory;
private ResponseFactory $responseFactory;

public function __construct(GuzzleHttp\ClientInterface $httpClient, ResponseFactory $responseFactory)
{
Expand All @@ -34,9 +30,9 @@ public function getAuthKeys(): Response\JsonWebKeySetCollection

try {
return $this->responseFactory->createFromArray(
GuzzleHttp\json_decode($response->getBody()->getContents(), true)
Utils::jsonDecode($response->getBody()->getContents(), true)
);
} catch (\InvalidArgumentException $exception) {
} catch (InvalidArgumentException $exception) {
throw new Exception\InvalidResponseException(
'Unable to decode response',
$exception->getCode(),
Expand Down
13 changes: 13 additions & 0 deletions src/Api/AppleApiClientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php declare(strict_types=1);

namespace Azimo\Apple\Api;

use Azimo\Apple\Api\Exception as ApiException;

interface AppleApiClientInterface
{
/**
* @throws ApiException\AppleApiExceptionInterface
*/
public function getAuthKeys(): Response\JsonWebKeySetCollection;
}
2 changes: 1 addition & 1 deletion src/Api/Enum/CryptographicAlgorithmEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Azimo\Apple\Api\Enum;

class CryptographicAlgorithmEnum
final class CryptographicAlgorithmEnum
{
public const KID_86D88KF = '86D88Kf';

Expand Down
2 changes: 1 addition & 1 deletion src/Api/Exception/InvalidResponseException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use InvalidArgumentException;

class InvalidResponseException extends InvalidArgumentException implements AppleApiExceptionInterface
final class InvalidResponseException extends InvalidArgumentException implements AppleApiExceptionInterface
{
}
2 changes: 1 addition & 1 deletion src/Api/Exception/PublicKeyFetchingFailedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use RuntimeException;

class PublicKeyFetchingFailedException extends RuntimeException implements AppleApiExceptionInterface
final class PublicKeyFetchingFailedException extends RuntimeException implements AppleApiExceptionInterface
{
}
2 changes: 1 addition & 1 deletion src/Api/Exception/ResponseValidationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use InvalidArgumentException;

class ResponseValidationException extends InvalidArgumentException implements AppleApiExceptionInterface
final class ResponseValidationException extends InvalidArgumentException implements AppleApiExceptionInterface
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use InvalidArgumentException;

class UnsupportedCryptographicAlgorithmException extends InvalidArgumentException implements AppleApiExceptionInterface
final class UnsupportedCryptographicAlgorithmException extends InvalidArgumentException implements AppleApiExceptionInterface
{
}
24 changes: 6 additions & 18 deletions src/Api/Response/JsonWebKeySet.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,33 @@ class JsonWebKeySet
{
/**
* The family of cryptographic algorithms used with the key.
*
* @var string
*/
private $kty;
private string $kty;

/**
* The unique identifier for the key.
*
* @var string
*/
private $kid;
private string $kid;

/**
* How the key was meant to be used; `sig` represents the signature.
*
* @var string
*/
private $use;
private string $use;

/**
* The specific cryptographic algorithm used with the key.
*
* @var string
*/
private $alg;
private string $alg;

/**
* The modulus for the RSA public key.
*
* @var string
*/
private $modulus;
private string $modulus;

/**
* The exponent for the RSA public key.
*
* @var string
*/
private $exponent;
private string $exponent;

public function __construct(string $kty, string $kid, string $use, string $alg, string $modulus, string $exponent)
{
Expand Down
7 changes: 1 addition & 6 deletions src/Api/Response/JsonWebKeySetCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,13 @@ class JsonWebKeySetCollection
/**
* @var JsonWebKeySet[]
*/
private $authKeys;
private array $authKeys;

public function __construct(array $authKeys)
{
$this->authKeys = $authKeys;
}

public function getAuthKeys(): array
{
return $this->authKeys;
}

public function getByCryptographicAlgorithm(string $algorithm): ?JsonWebKeySet
{
if (!CryptographicAlgorithmEnum::isSupported($algorithm)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use InvalidArgumentException;

class InvalidCryptographicAlgorithmException extends InvalidArgumentException implements AppleExceptionInterface
final class InvalidCryptographicAlgorithmException extends InvalidArgumentException implements AppleExceptionInterface
{
}
2 changes: 1 addition & 1 deletion src/Auth/Exception/InvalidJwtException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use InvalidArgumentException;

class InvalidJwtException extends InvalidArgumentException implements AppleExceptionInterface
final class InvalidJwtException extends InvalidArgumentException implements AppleExceptionInterface
{
}
2 changes: 1 addition & 1 deletion src/Auth/Exception/KeysFetchingFailedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use RuntimeException;

class KeysFetchingFailedException extends RuntimeException implements AppleExceptionInterface
final class KeysFetchingFailedException extends RuntimeException implements AppleExceptionInterface
{
}
2 changes: 1 addition & 1 deletion src/Auth/Exception/MissingClaimException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use OutOfBoundsException;

class MissingClaimException extends OutOfBoundsException implements AppleExceptionInterface
final class MissingClaimException extends OutOfBoundsException implements AppleExceptionInterface
{
}
9 changes: 0 additions & 9 deletions src/Auth/Exception/NotSignedTokenException.php

This file was deleted.

2 changes: 1 addition & 1 deletion src/Auth/Exception/ValidationFailedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use InvalidArgumentException;

class ValidationFailedException extends InvalidArgumentException implements AppleExceptionInterface
final class ValidationFailedException extends InvalidArgumentException implements AppleExceptionInterface
{
}
2 changes: 1 addition & 1 deletion src/Auth/Exception/VerificationFailedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

use InvalidArgumentException;

class VerificationFailedException extends InvalidArgumentException implements AppleExceptionInterface
final class VerificationFailedException extends InvalidArgumentException implements AppleExceptionInterface
{
}
Loading

0 comments on commit 435ed75

Please sign in to comment.