OAuth Login Without an SDK: The REST Flow for Any Game Engine
Oathwall ships a Unity SDK, and if you're building in Unity you should use it — it's less code and fewer edge cases to get wrong. But the SDK isn't where the login actually happens. Underneath, it's a handful of ordinary HTTPS requests and one deep link. If you're on Godot, Unreal, a custom C++ engine, or anything else without a packaged SDK, you can add the exact same social login by calling those requests yourself.
This page is the contract. Every endpoint, what it returns, and the one genuinely fiddly part — getting a one-time ticket back into your running game. No SDK required.
What the SDK is really doing
Strip away the C# and Oathwall login is five moves:
- Your game opens a hosted sign-in URL in the system browser.
- The player approves at the provider (Google, Discord, Steam…).
- Oathwall runs the OAuth exchange server-side and sends the browser back to your app with a short-lived ticket.
- Your game trades that ticket for an
access_tokenandrefresh_token. - You read the player from
/auth/me, and later refresh the session.
The client secret never touches your build — it lives on Oathwall's servers, which is the whole reason you don't need a backend of your own. The only thing your game carries is a public appKey. Every step above is a plain request you can make from any HTTP client.
The calls, without the SDK
Here's each move as a raw request. Base URL is https://sso.oathwall.com.
1. Start sign-in. Open this in the system browser (not an in-app webview — providers like Google block those):
https://sso.oathwall.com/auth/google/start?appKey=YOUR_PUBLIC_APP_KEY
The provider is a path segment. Swap google for discord, apple, steam, or any provider you enabled — that one string is the only difference between them. Add &sandbox=true to preview the flow against sandbox.oathwall.com without a real login while you're wiring things up.
2. Catch the ticket. After the player approves, Oathwall redirects the browser to the callback you registered, with the ticket on the query string:
mygame://auth?ticket=1f9c0a3e-…
Getting that URL back into your game is the platform-specific part — see below.
3. Exchange the ticket for tokens. One POST, and the ticket is single-use with a five-minute lifetime:
POST https://sso.oathwall.com/auth/consume
Content-Type: application/json
{ "ticket": "1f9c0a3e-…" }
Response:
{
"access_token": "eyJhbGci…",
"refresh_token": "9b1d…",
"expires_in": 3600
}
The access_token is a signed JWT good for one hour. The refresh_token is an opaque string you keep to extend the session. (If you're fuzzy on the difference, access vs. refresh tokens is a short read.)
4. Read the player. Send the access token as a bearer credential:
GET https://sso.oathwall.com/auth/me
Authorization: Bearer eyJhbGci…
Response:
{
"id": "a7c3…",
"email": "[email protected]",
"name": "Ada",
"picture": "https://…",
"provider": "google",
"linkedProviders": ["google"]
}
id is your stable player key — the value to hang cloud saves and leaderboards on. It doesn't change when the player's email does, and it's the same across providers once accounts are linked. Note that email, name, and picture can be null: Steam never returns an email, GitHub users often hide theirs, and not every provider sends an avatar.
5. Refresh before the hour is up. When the access token nears expiry, trade the refresh token for a fresh pair:
POST https://sso.oathwall.com/auth/refresh
Content-Type: application/json
{ "refresh_token": "9b1d…" }
You get a new access_token and a new refresh_token — the old refresh token is invalidated on use (rolling rotation). Store the new one and discard the old, or the next refresh will fail. Refresh tokens last 30 days, so a returning player skips the browser entirely: load the saved refresh token, call /auth/refresh, and you're signed in.
That's the entire integration. Two POSTs, two GETs, and a redirect.
Getting the ticket back into your game
Step 2 is the only part that isn't a plain HTTP call, because a game isn't a website sitting at a stable URL. OAuth ends in a browser redirect, and you need that redirect to land back inside your running app. How it lands depends on where your game runs.
You register a callback for your app in the Oathwall dashboard — either a full https:// URL or a custom URI scheme like mygame://. Oathwall appends ?ticket=… and sends the browser there. From that point it's your platform's job to deliver the URL to your process:
| Where the game runs | How the ticket arrives | What you register / set up |
|---|---|---|
| iOS / Android | Custom URI scheme deep link (mygame://auth?ticket=) |
Callback scheme in the dashboard, plus the URL scheme (iOS) or intent filter (Android) in your export |
| Desktop (Windows/macOS/Linux) | The same custom scheme, registered with the OS, which launches or focuses your game | Callback scheme in the dashboard, plus OS-level scheme registration in your installer |
| Web / WebGL | An ordinary HTTPS redirect to a page you control — read the ticket from location.search |
Callback set to your https:// URL; no deep link at all |
Two delivery paths exist under the hood, and it's worth knowing which you're on. If you set an explicit callback, Oathwall redirects straight to it. If you leave it default, Oathwall routes through a small hosted redirect page that uses JavaScript to open your mobile scheme and shows a tappable fallback link when the automatic hop doesn't fire — handy on mobile browsers that are cautious about auto-launching apps. For a custom engine, setting an explicit callback is usually the cleaner path; the hosted page is tuned for the mobile-first Unity case.
One value to get exactly right: the callback must match what's registered, character for character, or the flow dies before it starts — the same redirect URI discipline every OAuth integration lives by. If login "does nothing," a mismatched or unregistered callback is the first thing to check.
What you're signing up to build
Being honest about the trade: the SDK exists because these small pieces add up. Without it, you own:
- Opening the browser — a one-liner on most engines (
OS.shell_openin Godot,FPlatformProcess::LaunchURLin Unreal). - Catching the deep link — the platform table above. This is the real work, and it's where a custom engine spends its time.
- Token lifecycle — storing the refresh token somewhere safe (not plain player prefs), and refreshing the access token before it expires rather than after a call 401s.
- Silent resume — on launch, load the saved refresh token and call
/auth/refreshso returning players skip the browser.
None of these are hard, but they're four things the Unity SDK already does. If you're in Unity, take the SDK. If you're not, the flow above is complete and every endpoint is real — a few hundred lines and you have the same login the SDK provides.
For a worked example in a specific non-Unity engine, see adding OAuth login to a Godot game, which turns this contract into real GDScript.
Where this fits
Oathwall's service is engine-independent — the endpoints on this page don't care what rendered the button that called them. What's Unity-specific today is the packaged SDK, distributed on the Unity Asset Store. The free plan (one app, ten users) is enough to build and test the entire flow above before you commit to it, from whatever engine you're in.
Start with the complete Unity authentication guide for the full picture, OAuth 2.0 explained for the protocol underneath, or deep linking for the return trip in detail.
Frequently asked questions
- Can I use Oathwall without the Unity SDK?
- Yes. The Unity SDK is a convenience wrapper around a plain HTTP flow: open a sign-in URL, catch a one-time ticket on a deep link, and POST it to /auth/consume for tokens. Any engine or language that can open a URL and make HTTPS requests can do the same thing. You give up the SDK's ready-made plumbing, not any capability.
- What does the Unity SDK actually do for me that I'd have to build myself?
- It opens the system browser, registers and catches the deep link that carries the ticket, exchanges the ticket for tokens, stores the refresh token, and refreshes the access token before it expires. On another engine you write those four or five pieces yourself. None of them are large, but the deep-link handling is the part that varies most by platform.
- Is the appKey safe to ship in a non-Unity build?
- Yes. The appKey is a public identifier, the same as it is in a Unity build. It names your app so Oathwall knows which providers and callback to use, but it authorizes nothing on its own — the client secret stays on Oathwall's servers. Ship it in a Godot export, a native binary, or a web build without worry.
- Do I still avoid a backend if I integrate over REST?
- Yes. The confidential OAuth work — holding the client secret, exchanging the code, rotating refresh tokens — runs on Oathwall's servers whether you use the SDK or call the endpoints directly. Your game only ever handles the finished tokens, so there's still no auth server for you to run.