PHPackages                             surfoo/oauth2-geocaching - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. surfoo/oauth2-geocaching

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

surfoo/oauth2-geocaching
========================

Geocaching OAuth 2.0 Client Provider for The PHP League OAuth2-Client

3.0.0(5d ago)34.8k↑1012.5%21MITPHPPHP &gt;=8.2CI passing

Since Jun 19Pushed 5d ago2 watchersCompare

[ Source](https://github.com/Surfoo/oauth2-geocaching)[ Packagist](https://packagist.org/packages/surfoo/oauth2-geocaching)[ RSS](/packages/surfoo-oauth2-geocaching/feed)WikiDiscussions develop Synced 4d ago

READMEChangelog (10)Dependencies (19)Versions (15)Used By (1)

Geocaching Provider for OAuth 2.0 Client
========================================

[](#geocaching-provider-for-oauth-20-client)

[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![Total Downloads](https://camo.githubusercontent.com/9d4e0f1ce9665b7a66a3a5f0ee0c73038bcfbe4b1929b587bbd9c81e05e883cd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f737572666f6f2f6f61757468322d67656f63616368696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/Surfoo/oauth2-geocaching)

This package provides Geocaching OAuth 2.0 support for the PHP League's [OAuth 2.0 Client](https://github.com/thephpleague/oauth2-client).

Installation
------------

[](#installation)

To install, use composer:

```
composer require surfoo/oauth2-geocaching

```

Usage
-----

[](#usage)

Usage is the same as The League's OAuth client, using `\League\OAuth2\Client\Provider\Geocaching` as the provider.

### Authorization Code Flow

[](#authorization-code-flow)

```
use League\OAuth2\Client\Provider\Geocaching;

$provider = new Geocaching([
    'clientId'     => 'your-client-id',
    'clientSecret' => 'your-client-secret',
    'redirectUri'  => 'https://your-app.com/callback',
    'environment'  => 'production', // 'dev', 'staging', 'production'
]);

// Get authorization URL
$authUrl = $provider->getAuthorizationUrl(['scope' => '*']);
$_SESSION['oauth2state'] = $provider->getState();

// Redirect user to Geocaching
header('Location: ' . $authUrl);
exit;

// In your callback handler
if (!empty($_GET['code'])) {
    $token = $provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
    ]);

    $user = $provider->getResourceOwner($token);
    echo 'Hello ' . $user->getUsername() . '!';
}
```

### Environments

[](#environments)

EnvironmentDescriptionURLs`production`, `prod`Official Geocaching.com`geocaching.com`, `api.groundspeak.com``staging`, `qa`Staging environment`staging.geocaching.com``dev`, `development`, `docker`, `test`Local development`localhost:8000`### Custom URLs for Development

[](#custom-urls-for-development)

You can override environment URLs for your own development infrastructure:

```
use League\OAuth2\Client\Provider\Geocaching;
use League\OAuth2\Client\Provider\GeocachingConfig;

// Method 1: Direct URL overrides
$provider = new Geocaching([
    'clientId' => 'dev-client-id',
    'clientSecret' => 'dev-secret',
    'environment' => 'dev',
    'redirectUri' => 'http://localhost:3000/callback',

    // Custom URLs (override environment defaults)
    'domain' => 'https://my-geocaching.local',
    'apiDomain' => 'https://api.my-geocaching.local',
    'oAuthDomain' => 'https://oauth.my-geocaching.local',
]);

// Method 2: Using configuration helper
$config = GeocachingConfig::create('staging', [
    'apiDomain' => 'https://my-internal-api.company.com'
]);

$provider = new Geocaching(array_merge([
    'clientId' => 'client-id',
    'clientSecret' => 'client-secret',
    'redirectUri' => 'https://app.company.com/callback',
], $config));
```

#### Factory Helpers for Common Patterns

[](#factory-helpers-for-common-patterns)

```
use League\OAuth2\Client\Test\Factory\GeocachingTestFactory;

// Docker with custom port
$provider = GeocachingTestFactory::createForDocker(9000);
// Results in: http://localhost:9000, http://localhost:9000/api, http://localhost:9000/oauth

// Local development with custom base URL
$provider = GeocachingTestFactory::createForLocalDev('http://192.168.1.100:8080');
// Results in: http://192.168.1.100:8080, http://192.168.1.100:8080/api/v1, http://192.168.1.100:8080/oauth

// Completely custom URLs
$provider = GeocachingTestFactory::createWithCustomUrls(
    'https://geocaching.mycompany.local',
    'https://api.geocaching.mycompany.local',
    'https://oauth.geocaching.mycompany.local'
);
```

#### Advanced Configuration Examples

[](#advanced-configuration-examples)

**Docker Compose Setup:**

```
$provider = new Geocaching([
    'clientId' => $_ENV['GEOCACHING_CLIENT_ID'],
    'clientSecret' => $_ENV['GEOCACHING_CLIENT_SECRET'],
    'environment' => 'dev',
    'redirectUri' => 'http://localhost:3000/auth/callback',

    'domain' => 'http://geocaching-web:80',
    'apiDomain' => 'http://geocaching-api:8080/v1',
    'oAuthDomain' => 'http://geocaching-oauth:9090',
]);
```

**Enterprise Infrastructure:**

```
$config = GeocachingConfig::create('production', [
    'domain' => 'https://geocaching.internal.company.com',
    'apiDomain' => 'https://geocaching-api.internal.company.com/v2',
    'oAuthDomain' => 'https://sso.company.com/geocaching',
]);

$provider = new Geocaching(array_merge([
    'clientId' => $_ENV['COMPANY_GEOCACHING_CLIENT_ID'],
    'clientSecret' => $_ENV['COMPANY_GEOCACHING_CLIENT_SECRET'],
    'redirectUri' => 'https://myapp.company.com/oauth/callback',
], $config));
```

**Multi-Environment Deployment:**

```
$environment = $_ENV['APP_ENV'] ?? 'production';

switch ($environment) {
    case 'local':
        $provider = GeocachingTestFactory::createForLocalDev($_ENV['DEV_BASE_URL']);
        break;
    case 'staging':
        $config = GeocachingConfig::create('staging', [
            'apiDomain' => $_ENV['STAGING_API_URL'],
        ]);
        $provider = new Geocaching(array_merge($baseOptions, $config));
        break;
    case 'production':
    default:
        $provider = new Geocaching(array_merge($baseOptions, [
            'environment' => 'production'
        ]));
        break;
}
```

Take a look at `demo/index.php` for complete examples.

### Resource Owner (User Data)

[](#resource-owner-user-data)

After obtaining an access token, you can retrieve user information:

```
$user = $provider->getResourceOwner($token);

// Basic information
echo $user->getReferenceCode();    // 'PR1ABC2'
echo $user->getUsername();         // 'MyUsername'
echo $user->getFindCount();        // 150
echo $user->getHideCount();        // 5
echo $user->getFavoritePoints();   // 25

// Profile information
echo $user->getMembershipLevelId(); // 3 (Premium membership)
echo $user->getJoinedDate();       // '2020-01-15T10:30:00.123'
echo $user->getAvatarUrl();        // URL to user's avatar image
echo $user->getProfileUrl();       // URL to user's public profile
echo $user->getProfileText();      // User's profile description

// Additional data
$coordinates = $user->getHomeCoordinates(); // Array with lat/lon
$geocacheLimits = $user->getGeocacheLimits(); // API usage limits
$friendSharing = $user->getOptedInFriendSharing(); // Privacy setting
```

#### Custom Resource Owner Fields

[](#custom-resource-owner-fields)

By default, the provider requests a standard set of user fields. You can customize which fields to retrieve:

```
$provider->setResourceOwnerFields([
    'referenceCode',
    'username',
    'findCount',
    'hideCount',
    'favoritePoints',
    'membershipLevelId',
    'joinedDateUtc',
    'avatarUrl',
    'profileText'
    // Add any other fields supported by the Geocaching API
]);

$user = $provider->getResourceOwner($token);
// Now only the specified fields will be requested from the API
```

### Token Management &amp; Refresh

[](#token-management--refresh)

This package ships token lifecycle utilities you can plug into any PSR-18 client:

- `TokenSet`: lightweight DTO for access/refresh tokens with expiry helpers.
- `TokenStorageInterface`: implement to persist tokens (DB, cache, file) with locking.
- `TokenRefreshPlugin`: HTTPlug/PSR plugin that refreshes tokens on `401` and retries the original request.
- Exceptions for refresh/storage errors: `TokenRefreshException`, `RefreshTokenExpiredException`, `TokenStorageException`.

Basic wiring:

```
use Http\Client\Common\PluginClientFactory;
use League\OAuth2\Client\Plugin\TokenRefreshPlugin;
use League\OAuth2\Client\Provider\Geocaching;
use League\OAuth2\Client\Token\TokenStorageInterface;
use League\OAuth2\Client\Token\TokenSet;
use Nyholm\Psr7\Request;
use Psr\Log\NullLogger;

$provider = new Geocaching([
    'clientId'     => 'client_id',
    'clientSecret' => 'client_secret',
    'redirectUri'  => 'https://your-app.test/callback',
    'environment'  => 'production', // or staging/dev
]);

$storage = new class implements TokenStorageInterface {
    private ?TokenSet $tokens = null;
    public function getTokens(string $referenceCode): ?TokenSet { return $this->tokens; }
    public function saveTokens(string $referenceCode, TokenSet $tokens): void { $this->tokens = $tokens; }
    public function lockUser(string $referenceCode, int $timeoutSeconds = 30): bool { return true; }
    public function unlockUser(string $referenceCode): void {}
    public function isUserLocked(string $referenceCode): bool { return false; }
};

$refreshPlugin = new TokenRefreshPlugin(
    referenceCode: 'PR12345',
    storage: $storage,
    oauthProvider: $provider,
    logger: new NullLogger(),
    maxRetryAttempts: 3
);

$httpClient = (new PluginClientFactory())->createClient(
    \Http\Discovery\Psr18ClientDiscovery::find(),
    [$refreshPlugin]
);

$request = new Request('GET', $provider->apiDomain . '/v1/users/PR12345');
$response = $httpClient->sendRequest($request);
```

See `demo/index.php` for a full flow including PKCE, token storage, and a sample API call with automatic refresh. In production, replace the in-memory storage with a durable implementation.

Testing
-------

[](#testing)

```
$ ./vendor/bin/phpunit
```

License
-------

[](#license)

The MIT License (MIT). Please see [License File](https://github.com/Surfoo/oauth2-geocaching/blob/master/LICENSE) for more information.

###  Health Score

60

—

FairBetter than 98% of packages

Maintenance99

Actively maintained with recent releases

Popularity28

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity83

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~266 days

Recently: every ~250 days

Total

12

Last Release

5d ago

Major Versions

1.4.0 → 2.0.02023-08-13

1.4.1 → 3.0.02026-06-28

PHP version history (4 changes)1.4.0PHP ^7.3 || ^8.0

2.0.0PHP ^8.1

1.4.x-devPHP ^7.3 || ^8.1

3.0.0PHP &gt;=8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/aa8e8e1aa2d80dc4165f74c572bd01e4228cd7a7c82142d8651a62b0ab182fef?d=identicon)[Surfoo](/maintainers/Surfoo)

---

Top Contributors

[![Surfoo](https://avatars.githubusercontent.com/u/553659?v=4)](https://github.com/Surfoo "Surfoo (33 commits)")

---

Tags

apigeocachinggroundspeakoauth2restrest-apiclientoauth2authorizationpkcegeocachinggroundspeak

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/surfoo-oauth2-geocaching/health.svg)

```
[![Health](https://phpackages.com/badges/surfoo-oauth2-geocaching/health.svg)](https://phpackages.com/packages/surfoo-oauth2-geocaching)
```

###  Alternatives

[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)[thenetworg/oauth2-azure

Azure Active Directory OAuth 2.0 Client Provider for The PHP League OAuth2-Client

25310.7M83](/packages/thenetworg-oauth2-azure)[league/oauth2-google

Google OAuth 2.0 Client Provider for The PHP League OAuth2-Client

42223.4M176](/packages/league-oauth2-google)[stevenmaguire/oauth2-keycloak

Keycloak OAuth 2.0 Client Provider for The PHP League OAuth2-Client

2306.4M45](/packages/stevenmaguire-oauth2-keycloak)[patrickbussmann/oauth2-apple

Sign in with Apple OAuth 2.0 Client Provider for The PHP League OAuth2-Client

1152.8M12](/packages/patrickbussmann-oauth2-apple)[ekapusta/oauth2-esia

Allows to authenticate in ESIA and get authenticated individual personal information.

74195.7k1](/packages/ekapusta-oauth2-esia)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
