|
1 | 1 | <?php |
2 | 2 |
|
| 3 | +/** |
| 4 | + * Interactive OAuth (PKCE): open this script in a browser after starting a local server. |
| 5 | + * |
| 6 | + * 1) Register this exact Redirect URI in Penneo (OAuth client config): |
| 7 | + * http://127.0.0.1:8080/interactive_oauth_example.php |
| 8 | + * (or http://localhost:8080/... — must match character-for-character what you open in the browser) |
| 9 | + * |
| 10 | + * 2) From repository root: |
| 11 | + * export PENNEO_OAUTH_CLIENT_ID="..." |
| 12 | + * export PENNEO_OAUTH_CLIENT_SECRET="..." |
| 13 | + * php -S 127.0.0.1:8080 -t docs |
| 14 | + * |
| 15 | + * 3) Open in browser: http://127.0.0.1:8080/interactive_oauth_example.php |
| 16 | + * |
| 17 | + * Optional: PENNEO_OAUTH_REDIRECT_URI — if unset, defaults to 127.0.0.1 URL above. |
| 18 | + * Optional: PENNEO_OAUTH_ENV=sandbox|production (default sandbox). |
| 19 | + */ |
| 20 | + |
| 21 | +declare(strict_types=1); |
| 22 | + |
| 23 | +require_once dirname(__DIR__) . '/vendor/autoload.php'; |
| 24 | + |
3 | 25 | use Penneo\SDK\ApiConnector; |
4 | 26 | use Penneo\SDK\CaseFile; |
5 | 27 | use Penneo\SDK\OAuth\Config\Environment; |
|
10 | 32 |
|
11 | 33 | session_start(); |
12 | 34 |
|
13 | | -// set up where to store the tokens - either use the provided session storage |
14 | | -$tokenStorage = new SessionTokenStorage('optionalKeyToPlaceTokensInto'); |
| 35 | +function interactiveOauthFail(string $message): void |
| 36 | +{ |
| 37 | + if (PHP_SAPI === 'cli') { |
| 38 | + fwrite(STDERR, $message . PHP_EOL); |
| 39 | + } else { |
| 40 | + header('Content-Type: text/plain; charset=utf-8'); |
| 41 | + echo $message; |
| 42 | + } |
| 43 | + exit(1); |
| 44 | +} |
| 45 | + |
| 46 | +$clientId = getenv('PENNEO_OAUTH_CLIENT_ID') ?: ''; |
| 47 | +$clientSecret = getenv('PENNEO_OAUTH_CLIENT_SECRET') ?: ''; |
| 48 | +$redirectUri = getenv('PENNEO_OAUTH_REDIRECT_URI') ?: 'http://127.0.0.1:8080/interactive_oauth_example.php'; |
| 49 | +$environment = getenv('PENNEO_OAUTH_ENV') ?: Environment::SANDBOX; |
| 50 | + |
| 51 | +if ($clientId === '' || $clientSecret === '') { |
| 52 | + interactiveOauthFail( |
| 53 | + "Set environment variables before running:\n" |
| 54 | + . " export PENNEO_OAUTH_CLIENT_ID='...'\n" |
| 55 | + . " export PENNEO_OAUTH_CLIENT_SECRET='...'\n" |
| 56 | + . "Optional:\n" |
| 57 | + . " export PENNEO_OAUTH_REDIRECT_URI='http://127.0.0.1:8080/interactive_oauth_example.php'\n" |
| 58 | + . " export PENNEO_OAUTH_ENV=sandbox\n" |
| 59 | + . "\n" |
| 60 | + . 'The redirect URI must be registered identically in your Penneo OAuth client.' |
| 61 | + ); |
| 62 | +} |
| 63 | + |
| 64 | +if (!Environment::isSupported($environment)) { |
| 65 | + interactiveOauthFail("PENNEO_OAUTH_ENV must be 'sandbox' or 'production'. Got: {$environment}"); |
| 66 | +} |
15 | 67 |
|
16 | | -// or build a custom one by implementing the interface |
17 | | -// $tokenStorage = new class implements \Penneo\SDK\OAuth\Tokens\TokenStorage {}; |
| 68 | +$tokenStorage = new SessionTokenStorage('optionalKeyToPlaceTokensInto'); |
18 | 69 |
|
19 | 70 | $penneoOAuth = OAuthBuilder::start() |
20 | | - ->setEnvironment(Environment::SANDBOX) |
21 | | - ->setClientId('clientId') // <- the credentials provided by Penneo |
22 | | - ->setClientSecret('clientSecret') // <- |
23 | | - ->setRedirectUri('http://dev.php.local') // the exact URL you provided to Penneo |
| 71 | + ->setEnvironment($environment) |
| 72 | + ->setClientId($clientId) |
| 73 | + ->setClientSecret($clientSecret) |
| 74 | + ->setRedirectUri($redirectUri) |
24 | 75 | ->setTokenStorage($tokenStorage) |
25 | 76 | ->build(); |
26 | 77 |
|
27 | 78 | if (isset($_GET['error'])) { |
28 | | - // something went wrong - handle the error |
29 | | - print_r($_GET['error']); |
30 | | - exit; |
31 | | -} elseif (isset($_GET['code'])) { |
32 | | - // we are returning with a code after authorization |
| 79 | + $detail = $_GET['error_description'] ?? ''; |
| 80 | + header('Content-Type: text/plain; charset=utf-8'); |
| 81 | + echo 'OAuth error: ' . $_GET['error'] . ($detail !== '' ? "\n" . $detail : ''); |
| 82 | + exit(1); |
| 83 | +} |
| 84 | + |
| 85 | +if (isset($_GET['code'])) { |
| 86 | + if (empty($_SESSION['code_verifier'])) { |
| 87 | + interactiveOauthFail( |
| 88 | + "Missing PKCE code_verifier in session. Open this URL first in the same browser (no private window switch):\n" |
| 89 | + . $redirectUri |
| 90 | + ); |
| 91 | + } |
33 | 92 | try { |
34 | 93 | $penneoOAuth->exchangeAuthCode($_GET['code'], $_SESSION['code_verifier']); |
35 | 94 | } catch (PenneoSdkRuntimeException $e) { |
36 | | - /// something went wrong - handle the error |
37 | | - print_r($e); |
38 | | - exit; |
| 95 | + header('Content-Type: text/plain; charset=utf-8'); |
| 96 | + echo 'Token exchange failed: ' . $e->getMessage(); |
| 97 | + exit(1); |
39 | 98 | } |
40 | | - |
41 | | - // optionally, handle the returned state |
42 | | - print_r($_GET['state']); |
43 | 99 | } elseif (!$penneoOAuth->isAuthorized()) { |
44 | | - // set up the code challenge |
45 | 100 | $pkce = new PKCE(); |
46 | 101 | $codeVerifier = $pkce->getCodeVerifier(); |
47 | 102 | $_SESSION['code_verifier'] = $codeVerifier; |
48 | 103 |
|
49 | 104 | try { |
50 | | - // build the redirect URL for authorization |
51 | 105 | $url = $penneoOAuth->buildRedirectUrl( |
52 | 106 | ['full_access'], |
53 | 107 | $pkce->getCodeChallenge($codeVerifier) |
54 | 108 | ); |
55 | 109 |
|
| 110 | + if (PHP_SAPI === 'cli') { |
| 111 | + fwrite( |
| 112 | + STDOUT, |
| 113 | + "Open in a browser (after: php -S 127.0.0.1:8080 -t docs):\n" |
| 114 | + . $redirectUri . "\n\n" |
| 115 | + . "Or paste this authorize URL:\n" . $url . "\n" |
| 116 | + ); |
| 117 | + exit(0); |
| 118 | + } |
| 119 | + |
56 | 120 | header('Location: ' . $url); |
57 | 121 | exit; |
58 | 122 | } catch (PenneoSdkRuntimeException $e) { |
59 | | - // something went wrong - handle the error |
60 | | - var_dump($e); |
| 123 | + if (PHP_SAPI === 'cli') { |
| 124 | + var_dump($e); |
| 125 | + exit(1); |
| 126 | + } |
| 127 | + header('Content-Type: text/plain; charset=utf-8'); |
| 128 | + echo 'Could not build authorize URL: ' . $e->getMessage(); |
| 129 | + exit(1); |
61 | 130 | } |
62 | 131 | } |
63 | 132 |
|
64 | | -// the OAuth flow has finished, so we can start using the API |
65 | 133 | ApiConnector::initializeOAuth($penneoOAuth); |
66 | 134 |
|
67 | 135 | $casefile = new CaseFile(); |
68 | 136 | $casefile->setTitle('new test casefile from PHP'); |
69 | 137 | CaseFile::persist($casefile); |
| 138 | + |
| 139 | +header('Content-Type: text/plain; charset=utf-8'); |
| 140 | +echo 'OK — Case file created. id=' . (string) $casefile->getId() . PHP_EOL; |
0 commit comments