All requests go to the Truememory Auth base URL (see Before you start for prerequisites: base URL, CORS whitelisting, OAuth client IDs).
OAuth Sign-In (Google / Apple)
For OAuth, the frontend handles the provider interaction (consent screen, token retrieval) and the resulting provider token is exchanged with Truememory Auth for Truememory tokens. Truememory Auth creates or links the user account automatically on first sign-in — no separate registration step needed.
The examples below route that exchange through your own backend, so the returned refresh_token never reaches browser JavaScript — see Suggested implementation for why, and for the route handler these examples call. A frontend with no backend can call /auth/oauth/token directly; that trade-off is documented on the same page.
Flow
sequenceDiagram
accTitle: OAuth Sign-In Flow
accDescr: Shows how a frontend app authenticates a user via Google or Apple through Truememory Auth
participant User
participant Frontend
participant Provider as Google / Apple
participant Backend as Your backend
participant Truememory as Truememory Auth
participant GIP as Google Identity Platform
User->>Frontend: Click "Sign in with Google/Apple"
Frontend->>Provider: Open consent screen
Provider-->>Frontend: id_token (JWT)
Frontend->>Backend: POST /api/auth/oauth { provider, id_token }
Backend->>Truememory: POST /auth/oauth/token { provider, id_token }
Truememory->>GIP: Verify token
GIP-->>Truememory: Verified user info
Truememory->>Truememory: Create or link user account
Truememory-->>Backend: { id_token, refresh_token, expires_in, user }
Backend-->>Frontend: id_token in body, refresh_token in httpOnly cookie
Endpoint
POST https://your-auth-host/auth/oauth/token
Content-Type: application/json
{
"provider": "google",
"id_token": "<token-from-provider-sdk>"
}| Provider | provider value |
|---|---|
google |
|
| Apple | apple |
Response shape is the same as registration.
Google Sign-In (Frontend — React)
npm install @react-oauth/googleWrap your app root with the Google OAuth provider. The GOOGLE_CLIENT_ID is the OAuth 2.0 Client ID from your GCP project:
// providers.tsx
import { GoogleOAuthProvider } from "@react-oauth/google";
const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || "";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<GoogleOAuthProvider clientId={GOOGLE_CLIENT_ID}>
{children}
</GoogleOAuthProvider>
);
}Add the login button. It posts the Google credential to your own backend route, which exchanges it with Truememory Auth and sets the refresh-token cookie:
// login-page.tsx
import { GoogleLogin, type CredentialResponse } from "@react-oauth/google";
function LoginPage() {
const handleGoogleSuccess = async (response: CredentialResponse) => {
if (!response.credential) return;
const res = await fetch("/api/auth/oauth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
provider: "google",
id_token: response.credential,
}),
});
if (!res.ok) {
console.error("Sign-in failed");
return;
}
// Your route returns { id_token, expires_in, user } and keeps the
// refresh token in an httpOnly cookie. Hold the ID token in memory only.
const data = await res.json();
setIdToken(data.id_token, Number(data.expires_in));
};
return (
<GoogleLogin
onSuccess={handleGoogleSuccess}
onError={() => console.error("Google sign-in failed")}
size="large"
theme="outline"
/>
);
}Apple Sign-In (Frontend — React)
npm install react-apple-signin-authReplace APPLE_CLIENT_ID with the Service ID from your Apple Developer account. As with Google, the provider token goes to your own backend route:
import AppleSignin from "react-apple-signin-auth";
function LoginPage() {
const handleAppleSuccess = async (response: any) => {
const idToken = response.authorization?.id_token;
if (!idToken) return;
const res = await fetch("/api/auth/oauth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
provider: "apple",
id_token: idToken,
}),
});
if (!res.ok) {
console.error("Sign-in failed");
return;
}
const data = await res.json();
setIdToken(data.id_token, Number(data.expires_in));
};
return (
<AppleSignin
authOptions={{
clientId: APPLE_CLIENT_ID,
scope: "email name",
redirectURI: window.location.origin,
usePopup: true,
}}
onSuccess={handleAppleSuccess}
/>
);
}