Skip to content

Instantly share code, notes, and snippets.

@mingalevme
Last active September 15, 2022 10:01
Show Gist options
  • Select an option

  • Save mingalevme/c6fca8df82b40e5b60a009dc4b754e67 to your computer and use it in GitHub Desktop.

Select an option

Save mingalevme/c6fca8df82b40e5b60a009dc4b754e67 to your computer and use it in GitHub Desktop.

Revisions

  1. mingalevme revised this gist Sep 15, 2022. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions GenerateAccessToken.php
    Original file line number Diff line number Diff line change
    @@ -19,15 +19,15 @@ class GenerateAccessToken extends Command
    */
    public function handle(GuzzleClient $guzzle): int
    {
    $kid = $this->requireOption('kid');
    $iss = $this->requireOption('iss');
    $kid = $this->requireOption('kid'); // SignIn Key ID
    $iss = $this->requireOption('iss'); // Developer ID
    $aud = $this->getOption('aud') ?: 'https://appleid.apple.com';
    $sub = $this->requireOption('sub');
    $sub = $this->requireOption('sub'); // mobile app id
    $iat = intval($this->getOption('iat') ?: Carbon::now()->getTimestamp());
    $exp = intval($this->getOption('exp') ?: 86400 * 30);
    $privateKey = $this->requireOption('private-key');
    $exp = intval($this->getOption('exp') ?: 86400 * 30); // access token expiration timeout
    $privateKey = $this->requireOption('private-key'); // SignIn Key: "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"

    $code = $this->requireOption('code');
    $code = $this->requireOption('code'); // auth code from client

    $redirectUri = $this->requireOption('redirect-uri');

  2. mingalevme revised this gist Sep 15, 2022. 1 changed file with 46 additions and 20 deletions.
    66 changes: 46 additions & 20 deletions GenerateAccessToken.php
    Original file line number Diff line number Diff line change
    @@ -6,48 +6,74 @@

    use App\Console\Command;
    use App\Helpers\Jwt;
    use Carbon\Carbon;
    use GuzzleHttp\ClientInterface as GuzzleClient;
    use GuzzleHttp\Exception\GuzzleException;

    class GenerateAccessToken extends Command
    {
    protected $signature = 'apple:sing-in:token {code}';
    protected $signature = 'mfeed:apple:sing-in:token {--kid= : KID} {--iss=} {--aud=} {--sub=} {--iat=} {--exp=} {--private-key=} {--code=} {--redirect-uri=}';

    /**
    * @throws GuzzleException
    */
    public function handle(GuzzleClient $guzzle): int
    {
    //
    // DO NOT STORE APPLE SIGN IN CREDENTIALS IN THE CODE, THIS IS AN EXAMPLE
    //

    $kid = ''; // SignIn Key ID
    $privateKey = ' // SignIn Key
    -----BEGIN PRIVATE KEY-----
    ...
    -----END PRIVATE KEY-----';
    $kid = $this->requireOption('kid');
    $iss = $this->requireOption('iss');
    $aud = $this->getOption('aud') ?: 'https://appleid.apple.com';
    $sub = $this->requireOption('sub');
    $iat = intval($this->getOption('iat') ?: Carbon::now()->getTimestamp());
    $exp = intval($this->getOption('exp') ?: 86400 * 30);
    $privateKey = $this->requireOption('private-key');

    $iss = ''; // Developer ID
    $aud = 'https://appleid.apple.com';
    $sub = ''; // mobile app id
    $iat = time();
    $exp = $iat + 86400*30; // access token expiration timeout
    $code = $this->requireOption('code');

    $redirectUrl = 'https://example/apple/callback';
    $redirectUri = $this->requireOption('redirect-uri');

    $code = $this->argument('code');

    $clientSecret = (string) Jwt::issue($privateKey, $kid, $iss, $aud, $sub, $iat, $exp);
    $clientSecret = (string)Jwt::issue($privateKey, $kid, $iss, $aud, $sub, $iat, $exp);

    $response = $guzzle->request('POST', 'https://appleid.apple.com/auth/token', [
    'form_params' => [
    'client_id' => $sub,
    'code' => $code,
    'client_secret' => $clientSecret,
    'grant_type' => 'authorization_code',
    'redirect_uri' => $redirectUrl,
    'redirect_uri' => $redirectUri,
    ],
    ]);

    $this->line($response->getBody()->getContents());

    return 0;
    }

    private function requireOption(string $key): string
    {
    /** @var string|string[]|null $value */
    $value = $this->option($key);
    if (!$value) {
    $this->error("The \"--$key\" option does not exist.");
    exit(1);
    }
    if (!is_string($value)) {
    $this->error("The \"--$key\" option is a single value option.");
    exit(1);
    }
    return $value;
    }

    private function getOption(string $key): ?string
    {
    /** @var string|string[]|null $value */
    $value = $this->option($key);
    if (!$value) {
    return null;
    }
    if (!is_string($value)) {
    $this->error("The \"--$key\" option is a single value option.");
    exit(1);
    }
    return $value;
    }
    }
  3. mingalevme revised this gist Sep 15, 2022. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions Jwt.php
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    <?php

    // composer require lcobucci/jwt

    declare(strict_types=1);

    namespace App\Helpers;
  4. mingalevme created this gist Sep 15, 2022.
    53 changes: 53 additions & 0 deletions GenerateAccessToken.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,53 @@
    <?php

    declare(strict_types=1);

    namespace App\Console\Commands\Apple;

    use App\Console\Command;
    use App\Helpers\Jwt;
    use GuzzleHttp\ClientInterface as GuzzleClient;

    class GenerateAccessToken extends Command
    {
    protected $signature = 'apple:sing-in:token {code}';

    public function handle(GuzzleClient $guzzle): int
    {
    //
    // DO NOT STORE APPLE SIGN IN CREDENTIALS IN THE CODE, THIS IS AN EXAMPLE
    //

    $kid = ''; // SignIn Key ID
    $privateKey = ' // SignIn Key
    -----BEGIN PRIVATE KEY-----
    ...
    -----END PRIVATE KEY-----';

    $iss = ''; // Developer ID
    $aud = 'https://appleid.apple.com';
    $sub = ''; // mobile app id
    $iat = time();
    $exp = $iat + 86400*30; // access token expiration timeout

    $redirectUrl = 'https://example/apple/callback';

    $code = $this->argument('code');

    $clientSecret = (string) Jwt::issue($privateKey, $kid, $iss, $aud, $sub, $iat, $exp);

    $response = $guzzle->request('POST', 'https://appleid.apple.com/auth/token', [
    'form_params' => [
    'client_id' => $sub,
    'code' => $code,
    'client_secret' => $clientSecret,
    'grant_type' => 'authorization_code',
    'redirect_uri' => $redirectUrl,
    ],
    ]);

    $this->line($response->getBody()->getContents());

    return 0;
    }
    }
    29 changes: 29 additions & 0 deletions Jwt.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    <?php

    declare(strict_types=1);

    namespace App\Helpers;

    use Lcobucci\JWT\Builder;
    use Lcobucci\JWT\Signer\Ecdsa\Sha256;
    use Lcobucci\JWT\Signer\Key;
    use Lcobucci\JWT\Token;

    class Jwt
    {
    public static function issue(string $privateKey, string $kid, string $iss, string $aud, string $sub, int $iat, int $exp): Token
    {
    $signer = new Sha256();

    return (new Builder())
    ->issuedBy($iss)
    ->permittedFor($aud)
    ->relatedTo($sub)
    ->issuedAt($iat)
    ->expiresAt($exp)
    ->withHeader('kid', $kid)
    ->withHeader('alg', 'ES256')
    ->withHeader('type', 'JWT')
    ->getToken($signer, new Key($privateKey));
    }
    }