Artnet Backend
This app talks to the Artnet GraphQL gateway rather than Artsy's Metaphysics. This page describes the gateway endpoint, how authentication works via an SSO cookie, and how login/logout flow through the app.
GraphQL gateway
All GraphQL requests go to the Artnet gateway:
{gatewayURL}/graphql- Staging:
https://gateway.artnet-dev.com/graphql - The gateway base URL is configured per-environment (see the
EnvironmentModelstore slice) and the Relay network layer posts operations to{gatewayURL}/graphql.
The gateway exposes the current viewer through getCurrentUser:
type User {
id: ID!
displayName: String!
email: String!
}
type CurrentUserResult {
isLoggedIn: Boolean!
isReauthenticationRequired: Boolean!
user: User
}
type Query {
getCurrentUser: CurrentUserResult!
}This replaces the old Artsy me: Me root field. The Home screen reads getCurrentUser { user { … } } and renders the signed-in user's displayName (the email is shown in Settings, as "Logged in as: …", not on Home).
Authentication — SSO cookie
The gateway authenticates requests with an SSO session cookie (gatewaySession), not a bearer token — exactly like the web client. There is no credentials API and no email/password token endpoint, so the login UI is the Identity Server's hosted page, shown in an in-app WebView. Everything else in the app is native React Native; the WebView is only the sign-in handshake.
The app mirrors how a browser handles this — it lets the shared native cookie jar carry the session rather than reading the httpOnly cookie by hand:
ArtnetAuthWebViewopens{gatewayURL}/login?returnUrl={webURL}. The gateway runs the OpenID Connect authorization-code flow against the Identity Server and, on success, setsgatewaySessionand redirects back toreturnUrl(the main site).- The WebView uses
sharedCookiesEnabled(iOS →NSHTTPCookieStorage) and Android'sForwardingCookieHandler, so cookies set during sign-in are shared with the app'sfetch. Relay'sauthMiddlewaresetscredentials: "include", sogatewaySessionis sent automatically on{gatewayURL}/graphqlrequests — the gateway then resolvesgetCurrentUserfor the viewer.
Login
- Present the SSO WebView (the gateway
/loginflow → hosted IdP page). - Detect completion when the flow redirects back to the main site host (
webURL). - Flip the app into the signed-in group via
GlobalStore.actions.auth.setSignedIn(). The session itself lives in the native cookie jar; the store keeps anisSignedInflag plus the viewer'sid/email, whichhydrateUserfetches fromgetCurrentUser(using the shared cookie jar) for the feature-flag targeting context.hydrateUserruns on sign-in and on a cold start with a persisted session.
Logout
GlobalStore.actions.auth.signOut() clears the local isSignedIn flag, dropping the app back to the signed-out group. To also end the server-side session (and expire gatewaySession), open ArtnetAuthWebView in logout mode, which loads {gatewayURL}/logout. The logout entry point lives in the Settings tab (which also shows "Logged in as: …"); local state is cleared only once the WebView flow completes (onSuccess).
No native cookie library is used — cookie handling is entirely via the WebView
- the platform cookie jar. This keeps the native build free of unmaintained Gradle dependencies.
Staging & Cloudflare Access
The staging gateway (gateway.artnet-dev.com) sits behind Cloudflare Access. Direct programmatic access — for example, schema introspection via yarn sync-schema, or hitting the endpoint from scripts/CI — requires Cloudflare Access service-token headers:
CF-Access-Client-Id: <client-id>
CF-Access-Client-Secret: <client-secret>Requests from the app's WebView authenticate interactively through Cloudflare Access in the browser, so the service-token headers are only needed for non-interactive access to staging (schema sync, tooling, CI).
Relay compatibility
Relay works against the Artnet gateway for the query/fragment use cases this app needs (e.g. getCurrentUser on Home). This was verified, not assumed:
- The Relay compiler accepts the Artnet client schema and compiles the app's operations/fragments (
yarn relay), TypeScript type-checks, and the Relay-mocked tests pass. - At runtime Relay simply issues standard GraphQL POST requests to
{gatewayURL}/graphql, which the gateway (a spec-compliant Apollo Federation server) serves.Userexposes a globalid: ID!, sogetCurrentUsernormalizes cleanly into the Relay store.
Known limitations — the gateway schema does not currently follow two Relay conventions, so Relay's advanced features are not available out of the box:
- No
Nodeinterface /node(id: ID!)root field. Relay's@refetchable/useRefetchableFragmentand imperative id-based refetch depend on this, so they won't work until the gateway adds it. - No Relay Connection spec. List fields (e.g.
searchLots) return{ results, totalCount }rather thanedges/pageInfocursors, sousePaginationFragment/@connectioncannot be used; pagination must be handled manually (offset/limit) or the gateway must expose connections. - Types without a global
idare not normalized/deduplicated in the store (they still fetch fine).
None of these block login/logout or the Home getCurrentUser view. If we later need refetch or cursor pagination, that requires gateway-side schema additions (Node/connections) or client-side adapters.
A live network round-trip could not be exercised from the build environment (staging is behind Cloudflare Access and off the egress allowlist); the verification above is compile-, type-, and test-level plus the schema analysis.