Skip to main content

Authentication

Qumra apps use OAuth 2.0 for authorization. The SDK handles the entire flow automatically.

OAuth Flow

The following diagram illustrates the complete OAuth 2.0 flow between the Qumra Admin Panel, your app, and the Qumra OAuth server:

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│ Qumra Admin │────>│ Your App │────>│ Qumra OAuth │
│ Panel │ │ /auth/* │ │ Server │
└─────────────┘ └──────────────┘ └─────────────┘
│ │ │
│ 1. Opens iframe │ │
│───────────────────>│ │
│ │ 2. Redirect to │
│ │ OAuth │
│ │───────────────────>│
│ │ │
│ │ 3. Authorization │
│ │ code callback │
│ │<───────────────────│
│ │ │
│ │ 4. Exchange code │
│ │ for token │
│ │───────────────────>│
│ │ │
│ │ 5. Access token │
│ │<───────────────────│
│ │ │
│ 6. App loaded │ 7. Store session │
│<───────────────────│ │

Step-by-Step

  1. Store owner opens your app from the Qumra admin panel.
  2. Your app calls authenticate.admin(request) which checks for an existing session.
  3. SDK redirects to OAuth if no valid session is found.
  4. User authorizes your app, and Qumra redirects back to your callback_path.
  5. SDK exchanges the authorization code for an access token.
  6. Session is stored in your database via Prisma.
  7. App loads with the authenticated session available.

Admin Authentication

The authenticate.admin() method is the primary way to authenticate requests in your app. It behaves differently for GET and POST requests.

Use the loader to authenticate when the app is launched from the admin panel:

export async function loader({ request }: { request: Request }) {
const { admin, session, store } = await authenticate.admin(request);

// Use admin to make API calls
const data = await admin.graphql(`
query {
shop { name }
}
`);

return Response.json({ store, data });
}

The GET flow returns an AdminGetAuthResult:

interface AdminGetAuthResult {
admin: AdminGraphQLClient;
session: Session;
store: string;
data: JwtPayload;
}
FieldTypeDescription
adminAdminGraphQLClientPre-authenticated GraphQL client.
sessionSessionThe current session from the database.
storestringThe store domain (e.g. mystore.qumra.cloud).
dataJwtPayloadDecoded JWT payload from the session token.
Handle the Response Throw

Always handle the Response throw. During OAuth redirects, authenticate.admin() throws a Response object. Make sure to let it propagate or catch and re-throw it.

// DON'T do this -- it swallows the redirect
try {
const { admin } = await authenticate.admin(request);
} catch (error) {
// This catches the redirect Response!
return new Response("Error", { status: 500 });
}

// DO this -- let Response objects propagate
try {
const { admin } = await authenticate.admin(request);
} catch (error) {
if (error instanceof Response) throw error;
// Handle actual errors here
return new Response("Error", { status: 500 });
}

Next Steps