← Hive AxylCONTENT HISTORY
WHAT CHANGED
Update to Hive Axyl
Snapshot Oct 24, 2026 · 13:42 UTC · version 2.1.0
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Save Hive Axyl and check future changes in Following.
Up to 10 plugins free · no card required.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Implements first-run or returning guest login in Unity with the Hive Axyl SDK, through token exchange and session installation. Use for guest creation/restoration and retaining guest recovery credentials after failure. Does not implement saved access/refresh-token auto login.",
"included_files": [],
"name": "axyl-guest-login",
"skill_md_contents": "---\nname: axyl-guest-login\ndescription: \"Implements first-run or returning guest login in Unity with the Hive Axyl SDK, through token exchange and session installation. Use for guest creation/restoration and retaining guest recovery credentials after failure. Does not implement saved access/refresh-token auto login.\"\nlicense: Apache-2.0\nmetadata:\n author: Com2uS Platform Corporation\n sdk-version: 1.0.0\n engine: Unity 6000.0+\n---\n\n# Guest login\n\nCreates a guest on first run or restores the saved one, then installs an Axyl\nsession. The Installed SDK, SDK results, Axyl session and Login metadata sections\nbelow apply to every step.\n\n**Inputs:** Axyl `clientId`, the device's `deviceKey`, the saved\n`(PlayerId, GuestToken)` if any, and an optional app-server grant key.\n**App owns:** credential storage, guest UI, error display and result types.\n\n## Flow\n\n1. Create one PKCE pair for the attempt.\n2. **No saved credential:** `var created = await auth.CreateGuestAsync(new\n GuestCreateRequest { ClientId, DeviceKey, CodeChallenge, CodeChallengeMethod =\n CodeChallengeMethod.S256, GrantKey }, ctx)`. On `AuthCreateGuestResult.Success`,\n persist `(Data.PlayerId, Data.GuestToken)` **before any other check or step**:\n\n ```csharp\n if (!(created is AuthCreateGuestResult.Success ok) || string.IsNullOrEmpty(ok.Data.GuestToken))\n return; // no guest exists yet: report the result\n await store.SaveGuestAsync(ok.Data.PlayerId, ok.Data.GuestToken); // app-owned storage\n if (string.IsNullOrEmpty(ok.Data.AuthorizationCode))\n return; // guest kept: restore it next time\n ```\n3. **Saved credential:** call `auth.LoginGuestAsync(new GuestLoginRequest {\n GuestPlayerId, GuestToken, ClientId, DeviceKey, CodeChallenge,\n CodeChallengeMethod = CodeChallengeMethod.S256 })`.\n4. Exchange `Data.AuthorizationCode` with the step 1 verifier and install the\n session as the Axyl session section describes. A missing code is unusable.\n5. Return the login metadata and the guest credential to the app.\n\n## Keep the guest recoverable\n\n- Once creation returns a credential, every later exit keeps it: a missing code,\n a failed or unusable exchange, cancellation or a crash. The next attempt restores\n it with `LoginGuestAsync`; never create another guest because a later step failed.\n- A failed restore never falls back to creation, never deletes the saved\n credential and never reports first-run success; return the typed outcome to the\n app. `InvalidGuestToken` can mean a provider was linked to this guest (the first\n link invalidates the guest token); the app decides recovery, such as provider\n login.\n- `GrantKey` is a one-time key (60 s) that the app server gets from\n `/auth/v1/grant`. It is required when grant-key hardening is on and accepted when\n it is off (a sent key is always validated and consumed), so sending one is\n recommended. Never invent or replay a key; `GrantRequiredMissing` or\n `InvalidGrantKey` needs a fresh one.\n\n## Verify\n\n- [ ] No saved credential selects `CreateGuestAsync`, a saved one `LoginGuestAsync`;\n a failed restore never creates a guest.\n- [ ] The created `(PlayerId, GuestToken)` is persisted before the code exchange and\n survives every later failure or cancellation.\n- [ ] The code is exchanged once with the same attempt's verifier, followed by one\n `SetSession`.\n- [ ] Typed, unknown, technical and cancelled results keep their meaning; a stale\n attempt never replaces a newer session.\n- [ ] Refreshed session snapshots are persisted in order.\n- [ ] Source review, compilation, test doubles and device/server runs are reported\n separately.\n\n<!-- axyl-shared: core/installed-sdk.md -->\n\n## Installed SDK\n\n- Read `Packages/manifest.json`, the lock file and each resolved `package.json`.\n All `com.com2usplatform.hiveaxyl.*` packages must be the same release (UPM does\n not enforce this); `com.hive.axyl.*` packages are a release before 1.0.0-rc.9.\n- The installed SDK wins for APIs, types and contracts. If its release differs\n from this skill's `sdk-version`, apply a step only after its fields, result\n variants, platform support and failure behaviour match; otherwise stop at that\n step and report what is missing. Never change the installed version.\n- The app owns UI, storage, the device key and orchestration. Sample and recipe\n classes are not SDK APIs.\n\n<!-- /axyl-shared -->\n\n<!-- axyl-shared: core/results.md -->\n\n## SDK results\n\nMatch each call's concrete result and read `Success.Data` only after checking the\nfields the next step needs. The markers live in `Hive.Axyl.Contracts.Result`.\n\n| Result | Handling |\n|---|---|\n| `IUserCanceledOutcome` | The user dismissed OS or provider UI: stop this attempt quietly |\n| `IUnknownOutcome` | Keep `Code` and `RawJson`; never treat it as a known refusal or a success |\n| `IUntypedProblem` | Technical failure in `Problem` (`HiveError`): network, timeout or caller `Cancelled` |\n| Other typed variant | Only that call's documented meaning |\n\nPass `new ApiCallContext { Token = ct }` and check cancellation before each\nfollow-up call; a request cancelled in flight may still have taken effect. Never\nbranch on HTTP status, exception text or raw bodies, and never log tokens or\ncredentials.\n\n<!-- /axyl-shared -->\n\n<!-- axyl-shared: core/auth-session.md -->\n\n## Axyl session\n\n### Setup and inputs\n\n- Initialize once on the main thread with\n `HiveBootstrap.Initialize(config, b => b.AddAuth().AddToken())`; the default\n host is `https://core-api.hiveaxyl.com` (use `AddAuth(baseUrl)`/`AddToken(baseUrl)`\n only for a provisioned host). Call `AuthTokenRefresh.Enable(tokenHost, clientId)`\n once afterwards with the Token host. Never initialize inside a login.\n- Resolve `IAuthService`, `ITokenService` and `ISessionManager`; if one is missing,\n stop before any auth call.\n- `clientId` is the Axyl client ID, not a provider's. `deviceKey` is created once\n per device, persisted and reused: 22–64 printable ASCII (`^[!-~]{22,64}$`, UUID v4\n recommended); the SDK does not check it and the server rejects anything else.\n- Each attempt uses a fresh PKCE pair (`CodeChallengeMethod.S256`, base64url\n SHA-256 of a random verifier). Keep the verifier for this attempt's exchange only.\n\n### Authorization code to session\n\n1. `tokens.IssueTokenAsync(new AuthorizationCodeTokenRequest { ClientId,\n AuthorizationCode, CodeVerifier }, ctx)`.\n2. Continue only on `TokenIssueTokenResult.Success` with a nonempty `AccessToken`\n and `RefreshToken`. Expiry is Unix seconds now + `ExpiresIn`; if `ExpiresIn` is\n not positive, use the access token's JWT `exp`; with neither, the response is\n unusable.\n3. Check cancellation, then call\n `session.SetSession(accessToken, refreshToken, playerId, expiresAtSec)` once. A\n failed, unknown, cancelled or superseded attempt never overwrites the current\n session.\n\n`InvalidGrant`, `InvalidGrantExpired` and `InvalidGrantCodeChallenge` mean this\ncode or verifier is spent: start a new attempt, never replay the code.\n`TemporarilyUnavailable` is the only retryable issue outcome: back off before\nretrying (the interval is the app's choice). `InvalidClient` and `AppNotFound` are\nconfiguration errors.\n\n### Persistence and refresh\n\nSubscribe to `session.OnSessionRefreshed` before `SetSession` and persist each\nsnapshot in order. Core refreshes a live session; never add a refresh loop.\n`OnSessionExpired` means invalidation or an explicit clear: do not delete stored\ncredentials on app quit, transient or unknown failures, or storage `AccessDenied`.\n\n<!-- /axyl-shared -->\n\n<!-- axyl-shared: core/auth-account.md -->\n\n## Login metadata\n\n- `LoginResponseData` carries `PlayerId`, `CreatedAt`, `AuthorizationCode`,\n `ProviderList` (`ProviderId`, `ProviderUserId`, `ProviderIndex`) and `IsBlock`.\n Other responses carry only their own fields. Account creation\n (`GuestCreateResponseData`, `UsernameCreateResponseData`) returns `PlayerId`,\n `CreatedAt` and `AuthorizationCode` (guest also `GuestToken`), with no\n `ProviderList` or `IsBlock`. Token refresh returns tokens only, so earlier\n metadata stays stale and block status unknown. Never invent missing fields.\n- Return the supplied fields in an app-owned result tied to that player and\n attempt; the SDK session keeps only tokens, player ID and expiry. The app decides\n what to persist; authorization codes stay transient.\n- `ProviderList` lists the links at that response; it is not the provider catalog\n from `GetProviderListAsync`. `Guest` appears only for a pure guest. An empty list\n or a default value is not proof of no links.\n- `CreatedAt` is not a new-player flag. `IsBlock` is account status for the app to\n handle, not a transport failure.\n\n<!-- /axyl-shared -->\n"
}SHA-256 of public snapshot: 98613df98a1cb7117e605cae27c93fb993c1fc77ffe8be4cd94c1efa90b45a89