← 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 browser provider login through a Hive Axyl session in Unity: Google/X OAuth, Sign in with Apple on Android/Windows/WebGL and Steam OpenID. Use for WebAuth callbacks, redirect/loopback/state, the Axyl relay, provider exchange and Axyl handoff. Native Apple on iOS/macOS, Credential Manager, GPG and Steam tickets use their native routes.",
"included_files": [
{
"relative_path": "references/apple.md",
"size_in_bytes": 2323
},
{
"relative_path": "references/oauth.md",
"size_in_bytes": 4100
},
{
"relative_path": "references/steam-openid.md",
"size_in_bytes": 1876
}
],
"name": "axyl-provider-login-webauth",
"skill_md_contents": "---\nname: axyl-provider-login-webauth\ndescription: \"Implements browser provider login through a Hive Axyl session in Unity: Google/X OAuth, Sign in with Apple on Android/Windows/WebGL and Steam OpenID. Use for WebAuth callbacks, redirect/loopback/state, the Axyl relay, provider exchange and Axyl handoff. Native Apple on iOS/macOS, Credential Manager, GPG and Steam tickets use their native routes.\"\nlicense: Apache-2.0\nmetadata:\n author: Com2uS Platform Corporation\n sdk-version: 1.0.0\n engine: Unity 6000.0+\n---\n\n# Browser provider login (Google/X OAuth, Apple, Steam OpenID)\n\nBrowser acquisition through the WebAuth addon, then the Axyl provider join and\nsession. The Installed SDK, SDK results, Axyl session, Login metadata, Provider\njoin and Browser acquisition prerequisites sections below apply to every step.\n\n**Inputs:** Axyl `clientId`, `deviceKey`, the Axyl app ID for relayed callbacks and\nthe provider configuration: authorize endpoint, client ID (Apple: the Services ID),\nscope, registered redirect or return URL and any relay.\n**App owns:** provider registration, the callback page, UI and storage.\n\nRead only the requested provider's procedure:\n\n| Provider | Read | Covers |\n|---|---|---|\n| Google or X | [OAuth](references/oauth.md) | redirect and loopback URIs, state, callback, provider-code exchange |\n| Apple on Android, Windows or WebGL | [Apple](references/apple.md) | Services ID, Axyl relay, routing prefix on `state`, server-side exchange without provider PKCE |\n| Steam without the native client | [Steam OpenID](references/steam-openid.md) | return URL, Axyl relay and app callback, assertion checks, join inputs |\n\nKeep the selected mode, redirect and state together through acquisition; a\ncancellation or state mismatch stops before the join. Provider PKCE and Axyl PKCE\nare separate.\n\n## Verify\n\n- [ ] Google/X: state is validated before reading code or error; authorize and\n exchange use the same redirect URI; the exchange mode never switches silently.\n- [ ] Loopback: the redirect is allocated before opening, and a relay's state prefix\n is handled as configured.\n- [ ] Android: `hiveAxylWebAuthRedirectScheme` is set in `launcherTemplate.gradle`\n and a real redirect reaches the `OpenAsync` callback.\n- [ ] Apple: `state` carries the platform's routing prefix and is compared with\n `realState` first; the exchange sends the relay URL and no `CodeVerifier`;\n `user_cancelled_authorize` is a cancellation.\n- [ ] Steam OpenID: mode, return URL and claimed ID are validated, the assertion\n bytes are preserved and no OAuth exchange runs; on iOS/Android `return_to` is the\n relay with `relayTo` and a fresh `s`.\n- [ ] Relayed callbacks: `OpenRequest.RedirectUri` is `{appId}://oauth-callback`\n with the Axyl app ID, Android registers that scheme on the callback Activity, and\n a real callback reaches the app on iOS and Android.\n- [ ] WebGL keeps the originating user gesture; real callback, bridge and server\n validation are reported separately from simulated callbacks.\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\n<!-- axyl-shared: core/provider-join.md -->\n\n## Provider join\n\nTurns an acquired provider credential into an Axyl session. Acquisition, and any\nprovider-code exchange, must have succeeded first; a cancelled, failed or unknown\nacquisition stops before this join.\n\n| Route | `Provider` | `ProviderToken` | `ProviderUserId` |\n|---|---|---|---|\n| Apple native | `SigninApple` | `IdentityToken` | `UserIdentifier` |\n| Google Credential Manager | `Google` | `IdToken` | `UniqueId` |\n| Google/X/Apple browser, Play Games | `Google`, `X`, `SigninApple`, `GooglePlayGames` | `ProviderToken` from `ExchangeProviderTokenAsync` (direct exchange: Google `id_token`, X access token) | its `ProviderUserId` (direct exchange: `sub`, `data.id`) |\n| Steam native | `Steam` | `TicketHex` | the app's SteamID64; confirm server support before omitting it |\n| Steam OpenID | `Steam` | the callback query without the leading `?` or fragment, bytes unchanged | SteamID64 from `openid.claimed_id` |\n\nNever cast another enum to `Provider` by number.\n\n1. New Axyl PKCE pair, separate from any provider OAuth PKCE or state.\n2. `auth.LoginProviderAsync(new ProviderLoginRequest { ProviderId, ProviderUserId,\n ProviderToken, ClientId, DeviceKey, CodeChallenge,\n CodeChallengeMethod = CodeChallengeMethod.S256 }, ctx)`.\n3. On `AuthLoginProviderResult.Success`, exchange `Data.AuthorizationCode` with this\n Axyl verifier and install the session.\n\n`ProviderTokenError`, `ProviderConfigNotFound`, `ProviderClientInfoNotExists`,\n`ProviderRequestFailed` and app, service or IP outcomes keep their own meaning;\nnever switch route or create a guest because of them. Login has no typed\n`ProviderNotSupported`: that code arrives as `IUnknownOutcome`. Show block UI only\nfrom `IsBlock`. A native Steam ticket stays alive until backend validation settles,\nthen its owner releases it on the main thread.\n\n<!-- /axyl-shared -->\n\n<!-- axyl-shared: auth/browser.md -->\n\n## Browser acquisition prerequisites\n\nRequire `AddWebAuth()` and a resolved `IExternalUserAgent` on the target\nplayer. Google/X OAuth, Apple and Steam OpenID differ in configuration, callback\nvalidation and exchange; apply only the selected provider's procedure.\n\n### App prerequisites\n\nWebGL must open the popup in the originating user gesture; do not insert an\nunrelated await before `OpenAsync`. The app ships a callback page compatible\nwith the SDK bridge and origin checks. The sample's file/hosting layout is an\nexample; a usable registered callback and bridge integration are requirements.\nOn Android, set `hiveAxylWebAuthRedirectScheme` in the app module's\n`launcherTemplate.gradle` to the scheme of `OpenRequest.RedirectUri`. Do not put\nit in `mainTemplate.gradle`; the application module must resolve the library's\nplaceholder. A second callback scheme (such as the Axyl relay's app callback next to\nan OAuth redirect scheme) needs its own intent-filter on the same WebAuth callback\nActivity, declared in an app-owned Android library manifest. Verify that a real\nAndroid redirect reaches the `OpenAsync` callback. Endpoints, UI and credential-source\nclass design remain app choices.\n\n### Axyl relay\n\nSteam on iOS/Android and Apple outside iOS/macOS return through the relay Axyl\noperates at `relayBase` = `{baseUrl}/auth/v1/provider/callback`, where `{baseUrl}` is\nthe Axyl server host. The app's own callback is `appCallback` =\n`{appId}://oauth-callback` with the **Axyl app ID**, not the Android package name\n(the relay answers a package name with `app_not_found`). Pass `appCallback` as\n`OpenRequest.RedirectUri`, never the relay URL. iOS matches that scheme itself;\nAndroid needs it registered as above; WebGL and Windows loopback use their own\ncallback and no app scheme. The app still checks that the callback it received is\nthe one this attempt expected.\n\n<!-- /axyl-shared -->\n"
}SHA-256 of public snapshot: 1173fb4dffdb8c5d02c93aff8dde982ace1fa7e5e79f70d4d78c2ccb75c6ecab