Skip to content

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 EnvironmentModel store slice) and the Relay network layer posts operations to {gatewayURL}/graphql.

The gateway exposes the current viewer through getCurrentUser:

graphql
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).

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:

  • ArtnetAuthWebView opens {gatewayURL}/login?returnUrl={webURL}. The gateway runs the OpenID Connect authorization-code flow against the Identity Server and, on success, sets gatewaySession and redirects back to returnUrl (the main site).
  • The WebView uses sharedCookiesEnabled (iOS → NSHTTPCookieStorage) and Android's ForwardingCookieHandler, so cookies set during sign-in are shared with the app's fetch. Relay's authMiddleware sets credentials: "include", so gatewaySession is sent automatically on {gatewayURL}/graphql requests — the gateway then resolves getCurrentUser for the viewer.

Login

  1. Present the SSO WebView (the gateway /login flow → hosted IdP page).
  2. Detect completion when the flow redirects back to the main site host (webURL).
  3. 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 an isSignedIn flag plus the viewer's id/email, which hydrateUser fetches from getCurrentUser (using the shared cookie jar) for the feature-flag targeting context. hydrateUser runs 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. User exposes a global id: ID!, so getCurrentUser normalizes 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 Node interface / node(id: ID!) root field. Relay's @refetchable/useRefetchableFragment and 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 than edges/pageInfo cursors, so usePaginationFragment / @connection cannot be used; pagination must be handled manually (offset/limit) or the gateway must expose connections.
  • Types without a global id are 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.

Released under the MIT License.