Skip to content

Instantly share code, notes, and snippets.

@jrtashjian
Last active March 10, 2020 05:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jrtashjian/326f9ed7162988b651a035f7a724831b to your computer and use it in GitHub Desktop.
Save jrtashjian/326f9ed7162988b651a035f7a724831b to your computer and use it in GitHub Desktop.
OAuth2 ESI Client
EVEONLINE_KEY=**your application key**
EVEONLINE_SECRET=**your application secret**
EVEONLINE_REDIRECT_URI=http://yourapp.tld/auth/eve/callback/
<?php
namespace App;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Route;
class Character extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'user_id',
'character_id',
'character_name',
'corporation_id',
'alliance_id',
'token',
'refresh_token',
'expires_on',
'character_owner_hash',
'scopes',
];
public function getTokenAttribute($value)
{
return $this->expires_on > Carbon::now() ? $value : null;
}
public function getScopesAttribute()
{
return explode(' ', $this->attributes['scopes']);
}
public function getImageUrlAttribute()
{
return sprintf(
'https://imageserver.eveonline.com/Character/%s_512.jpg',
$this->character_id
);
}
public function getSwitchToRouteUrlAttribute()
{
$current_character = Route::current()->parameter('character');
$current_route = Route::currentRouteName();
if (strpos($current_route, 'character') === false) {
return null;
}
return $this->character_id === $current_character->character_id
? null
: route($current_route, [ 'character' => $this->character_id ]);
}
}
<?php
/**
* Setup the ESI API Requests with the proper cache for every request.
*
* @param \EsiClient\EsiClient\Api $api The Swagger API class constant we are using.
* @param string $access_token The access_token for authenticating API requests.
*
* @return \EsiClient\EsiClient\Configuration
*/
function esiRequest($api, $access_token = '')
{
$stack = \GuzzleHttp\HandlerStack::create();
$stack->push(
new \Kevinrob\GuzzleCache\CacheMiddleware(
new \Kevinrob\GuzzleCache\Strategy\PrivateCacheStrategy(
new \Kevinrob\GuzzleCache\Storage\LaravelCacheStorage(
\Illuminate\Support\Facades\Cache::store()
)
)
),
'cache'
);
$httpClient = new \GuzzleHttp\Client(['handler' => $stack]);
$apiInstance = new $api($httpClient);
if ($access_token) {
$apiInstance->getConfig()->setAccessToken($access_token);
}
$apiInstance->getConfig()->setUserAgent('EVE-Industry-Dashboard/1.0.0/php');
return $apiInstance;
}
/**
* @param \App\Character $character
*
* @return mixed
*/
function getCharacterAccessToken(\App\Character $character)
{
if (! $character->token) {
$provider = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => config('services.eveonline.client_id'),
'clientSecret' => config('services.eveonline.client_secret'),
'redirectUri' => config('services.eveonline.redirect'),
'urlAuthorize' => 'https://login.eveonline.com/oauth/authorize',
'urlAccessToken' => 'https://login.eveonline.com/oauth/token',
'urlResourceOwnerDetails' => 'https://login.eveonline.com/oauth/verify',
]);
try {
$refresh_token_data = $provider->getAccessToken('refresh_token', [
'refresh_token' => $character->refresh_token,
]);
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $error) {
dd($error->getMessage());
}
// Update Character with new access token
$character->token = $refresh_token_data->getToken();
$character->expires_on = date('Y-m-d H:i:s', $refresh_token_data->getExpires());
$character->save();
}
return $character->token;
}
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use EsiClient\ApiException;
use EsiClient\EsiClient\Api\CharacterApi;
use EsiClient\EsiClient\Api\CorporationApi;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class EveAccountController extends Controller
{
private $provider;
public function __construct()
{
// https://docs.microsoft.com/en-us/outlook/rest/php-tutorial#implementing-oauth2
// https://oauth2-client.thephpleague.com/usage/
$this->provider = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => config('services.eveonline.client_id'),
'clientSecret' => config('services.eveonline.client_secret'),
'redirectUri' => config('services.eveonline.redirect'),
'urlAuthorize' => 'https://login.eveonline.com/oauth/authorize',
'urlAccessToken' => 'https://login.eveonline.com/oauth/token',
'urlResourceOwnerDetails' => 'https://login.eveonline.com/oauth/verify',
]);
}
public function redirectToCharacterProvider()
{
return redirect(
$this->provider->getAuthorizationUrl([
'scope' => implode(' ', config('services.eveonline.character_scopes'))
])
);
}
public function handleProviderCallback(Request $request)
{
try {
$access_token = $this->provider->getAccessToken('authorization_code', [
'code' => $request->query('code'),
]);
$resource_owner = $this->provider->getResourceOwner($access_token)->toArray();
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $error) {
dd($error->getMessage());
}
$character_id = $resource_owner['CharacterID'];
try {
// Get public character details from ESI.
$CharacterApi = esiRequest(CharacterApi::class);
$character = $CharacterApi->getCharactersCharacterId($character_id);
} catch (ApiException $error) {
dd($error->getMessage());
}
// Store public character details into the database.
Character::updateOrCreate(
[ 'character_owner_hash' => $resource_owner['CharacterOwnerHash'] ],
[
'user_id' => Auth::id(),
'character_id' => $character_id,
'character_name' => $resource_owner['CharacterName'],
'corporation_id' => $character->getCorporationId(),
'alliance_id' => $character->getAllianceId(),
'token' => $access_token->getToken(),
'refresh_token' => $access_token->getRefreshToken(),
'expires_on' => date('Y-m-d H:i:s', $access_token->getExpires()),
'scopes' => $resource_owner['Scopes'],
]
);
// Get corporation information from ESI.
$CorporationApi = esiRequest(CorporationApi::class);
try {
$corporation = $CorporationApi->getCorporationsCorporationId($character->getCorporationId());
} catch (ApiException $error) {
return "Exception when calling CorporationApi->getCorporationsCorporationId: " . $error->getMessage() . PHP_EOL;
}
// Store public corporation details into the database and link to character model.
Corporation::updateOrCreate(
[ 'id' => $character->getCorporationId() ],
[
'name' => $corporation->getName(),
'ticker' => $corporation->getTicker(),
'description' => $corporation->getDescription(),
'member_count' => $corporation->getMemberCount(),
'tax_rate' => $corporation->getTaxRate(),
]
);
return redirect()->route('home');
}
}
'eveonline' => [
'client_id' => env('EVEONLINE_KEY'),
'client_secret' => env('EVEONLINE_SECRET'),
'redirect' => env('EVEONLINE_REDIRECT_URI'),
'character_scopes' => env('EVEONLINE_SCOPES_CHARACTER', [
'publicData',
]),
],
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCharactersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('characters', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('character_id');
$table->string('character_name');
$table->unsignedBigInteger('corporation_id')->nullable();
$table->unsignedBigInteger('alliance_id')->nullable();
$table->text('token');
$table->text('refresh_token');
$table->timestamp('expires_on')->nullable();
$table->text('scopes');
$table->string('character_owner_hash')->unique();
$table->timestamps();
$table->index('user_id');
$table->index('character_id');
$table->index('corporation_id');
$table->index('alliance_id');
$table->foreign('user_id')->references('id')->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('characters');
}
}
Route::get('/auth/eve', 'Auth\EveAccountController@redirectToCharacterProvider');
Route::get('/auth/eve/callback', 'Auth\EveAccountController@handleProviderCallback');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment