--- title: Admin description: >- Contains functions for authenticating and interacting with the Admin API. This function can handle requests for apps embedded in the Admin, Admin extensions, or non-embedded apps. api_version: v1 api_name: shopify-app-remix source_url: html: 'https://shopify.dev/docs/api/shopify-app-remix/v1/authenticate/admin' md: 'https://shopify.dev/docs/api/shopify-app-remix/v1/authenticate/admin.md' --- # Admin Contains functions for authenticating and interacting with the Admin API. This function can handle requests for apps embedded in the Admin, Admin extensions, or non-embedded apps. ## authenticate.​admin(**[request](#authenticateadmin-propertydetail-request)**​) Authenticates requests coming from the Shopify admin. The shape of the returned object changes depending on the `isEmbeddedApp` config. ### Parameters * **request** **Request** **required** ### Returns * **Promise\>** ### AdminContext ```ts Config['isEmbeddedApp'] extends false ? NonEmbeddedAdminContext : EmbeddedAdminContext ``` ### NonEmbeddedAdminContext * session The session for the user who made the request. This comes from the session storage which \`shopifyApp\` uses to store sessions in your database of choice. Use this to get shop or user-specific data. ```ts Session ``` * admin Methods for interacting with the GraphQL / REST Admin APIs for the store that made the request. ```ts AdminApiContext ``` * billing Billing methods for this store, based on the plans defined in the \`billing\` config option. ```ts BillingContext ``` * cors A function that ensures the CORS headers are set correctly for the response. ```ts EnsureCORSFunction ``` ### AdminApiContext * rest Methods for interacting with the Shopify Admin REST API There are methods for interacting with individual REST resources. You can also make \`GET\`, \`POST\`, \`PUT\` and \`DELETE\` requests should the REST resources not meet your needs. ```ts RestClientWithResources ``` * graphql Methods for interacting with the Shopify Admin GraphQL API ```ts GraphQLClient ``` ### RestClientWithResources ```ts RemixRestClient & {resources: Resources} ``` ### BillingContext * require Checks if the shop has an active payment for any plan defined in the \`billing\` config option. ```ts (options: RequireBillingOptions) => Promise ``` * request Requests payment for the plan. ```ts (options: RequestBillingOptions) => Promise ``` * cancel Cancels an ongoing subscription, given its ID. ```ts (options: CancelBillingOptions) => Promise ``` ### RequireBillingOptions * plans The plans to check for. Must be one of the values defined in the \`billing\` config option. ```ts (keyof Config["billing"])[] ``` * onFailure How to handle the request if the shop doesn't have an active payment for any plan. ```ts (error: any) => Promise ``` * isTest ```ts boolean ``` ### RequestBillingOptions * plan The plan to request. Must be one of the values defined in the \`billing\` config option. ```ts keyof Config["billing"] ``` ### CancelBillingOptions * subscriptionId The ID of the subscription to cancel. ```ts string ``` * prorate Whether to prorate the cancellation. ```ts boolean ``` * isTest ```ts boolean ``` ### EmbeddedAdminContext * sessionToken The decoded and validated session token for the request. Returned only if \`isEmbeddedApp\` is \`true\`. ```ts JwtPayload ``` * redirect A function that redirects the user to a new page, ensuring that the appropriate parameters are set for embedded apps. Returned only if \`isEmbeddedApp\` is \`true\`. ```ts RedirectFunction ``` * session The session for the user who made the request. This comes from the session storage which \`shopifyApp\` uses to store sessions in your database of choice. Use this to get shop or user-specific data. ```ts Session ``` * admin Methods for interacting with the GraphQL / REST Admin APIs for the store that made the request. ```ts AdminApiContext ``` * billing Billing methods for this store, based on the plans defined in the \`billing\` config option. ```ts BillingContext ``` * cors A function that ensures the CORS headers are set correctly for the response. ```ts EnsureCORSFunction ``` ### RedirectFunction * url ```ts string ``` * init ```ts RedirectInit ``` TypedResponse\ ```ts TypedResponse ``` ### RedirectInit ```ts number | (ResponseInit & {target?: RedirectTarget}) ``` ### RedirectTarget ```ts '_self' | '_parent' | '_top' ``` Examples ### Examples * #### Using the decoded session token ##### Description Get user-specific data using the \`sessionToken\` object. ##### shopify.server.ts ```typescript import { shopifyApp } from "@shopify/shopify-app-remix/server"; const shopify = shopifyApp({ // ...etc useOnlineTokens: true, }); export default shopify; export const authenticate = shopify.authenticate; ``` ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; import { getMyAppData } from "~/db/model.server"; export const loader = async ({ request }: LoaderArgs) => { const { sessionToken } = await authenticate.public.checkout( request ); return json(await getMyAppData({user: sessionToken.sub})); }; ``` * #### Redirecting to an app route ##### Description Use the \`redirect\` helper to safely redirect between pages. ##### /app/routes/admin/my-route.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { session, redirect } = await authenticate.admin(request); return redirect("/"); }; ``` * #### Redirecting outside of Shopify admin ##### Description Pass in a \`target\` option of \`\_top\` or \`\_parent\` to go to an external URL. ##### /app/routes/admin/my-route.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { session, redirect } = await authenticate.admin(request); return redirect("/", { target: '_parent' }); }; ``` * #### Using offline sessions ##### Description Get your app's shop-specific data using an offline session. ##### shopify.server.ts ```typescript import { shopifyApp } from "@shopify/shopify-app-remix/server"; const shopify = shopifyApp({ // ...etc }); export default shopify; export const authenticate = shopify.authenticate; ``` ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; import { getMyAppData } from "~/db/model.server"; export const loader = async ({ request }: LoaderArgs) => { const { session } = await authenticate.admin(request); return json(await getMyAppData({shop: session.shop)); }; ``` * #### Using online sessions ##### Description Get your app's user-specific data using an online session. ##### shopify.server.ts ```typescript import { shopifyApp } from "@shopify/shopify-app-remix/server"; const shopify = shopifyApp({ // ...etc useOnlineTokens: true, }); export default shopify; export const authenticate = shopify.authenticate; ``` ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; import { getMyAppData } from "~/db/model.server"; export const loader = async ({ request }: LoaderArgs) => { const { session } = await authenticate.admin(request); return json(await getMyAppData({user: session.onlineAccessInfo!.id})); }; ``` * #### Setting CORS headers for a admin request ##### Description Use the \`cors\` helper to ensure your app can respond to requests from admin extensions. ##### /app/routes/admin/my-route.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; import { getMyAppData } from "~/db/model.server"; export const loader = async ({ request }: LoaderArgs) => { const { session, cors } = await authenticate.admin(request); return cors(json(await getMyAppData({user: session.onlineAccessInfo!.id}))); }; ``` * #### Using REST resources ##### Description Getting the number of orders in a store using REST resources. ##### /app/shopify.server.ts ```typescript import { shopifyApp } from "@shopify/shopify-app-remix/server"; import { restResources } from "@shopify/shopify-api/rest/admin/2023-07"; const shopify = shopifyApp({ restResources, // ...etc }); export default shopify; export const authenticate = shopify.authenticate; ``` ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { admin, session } = await authenticate.admin(request); return json(admin.rest.resources.Order.count({ session })); }; ``` * #### Performing a GET request to the REST API ##### Description Use \`admin.rest.\\` to make custom requests to the API. ##### /app/shopify.server.ts ```typescript import { shopifyApp } from "@shopify/shopify-app-remix/server"; import { restResources } from "@shopify/shopify-api/rest/admin/2023-04"; const shopify = shopifyApp({ restResources, // ...etc }); export default shopify; export const authenticate = shopify.authenticate; ``` ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs, json } from "@remix-run/node"; import { authenticate } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { admin, session } = await authenticate.admin(request); const response = await admin.rest.get({ path: "/customers/count.json" }); const customers = await response.json(); return json({ customers }); }; ``` * #### Querying the GraphQL API ##### Description Use \`admin.graphql\` to make query / mutation requests. ##### Example ```typescript import { ActionArgs } from "@remix-run/node"; import { authenticate } from "../shopify.server"; export async function action({ request }: ActionArgs) { const { admin } = await authenticate.admin(request); const response = await admin.graphql( `#graphql mutation populateProduct($input: ProductInput!) { productCreate(input: $input) { product { id } } }`, { variables: { input: { title: "Product Name" } } } ); const productData = await response.json(); return json({ data: productData.data }); } ``` * #### Requesting billing right away ##### Description Call \`billing.request\` in the \`onFailure\` callback to immediately request payment. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { billing } = await authenticate.admin(request); await billing.require({ plans: [MONTHLY_PLAN], isTest: true, onFailure: async () => billing.request({ plan: MONTHLY_PLAN }), }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### Using a plan selection page ##### Description Redirect to a different page in the \`onFailure\` callback, where the merchant can select a billing plan. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs, redirect } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN, ANNUAL_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { billing } = await authenticate.admin(request); const billingCheck = await billing.require({ plans: [MONTHLY_PLAN, ANNUAL_PLAN], isTest: true, onFailure: () => redirect('/select-plan'), }); const subscription = billingCheck.appSubscriptions[0]; console.log(`Shop is on ${subscription.name} (id ${subscription.id})`); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### Using a custom return URL ##### Description Change where the merchant is returned to after approving the purchase using the \`returnUrl\` option. ##### /app/routes/\*\*\\/\*.ts ```typescript import { LoaderArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { billing } = await authenticate.admin(request); await billing.require({ plans: [MONTHLY_PLAN], onFailure: async () => billing.request({ plan: MONTHLY_PLAN, isTest: true, returnUrl: '/billing-complete', }), }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` * #### Cancelling a subscription ##### Description Use the \`billing.cancel\` function to cancel an active subscription with the id returned from \`billing.require\`. ##### /app/routes/cancel-subscription.ts ```typescript import { LoaderArgs } from "@remix-run/node"; import { authenticate, MONTHLY_PLAN } from "../shopify.server"; export const loader = async ({ request }: LoaderArgs) => { const { billing } = await authenticate.admin(request); const billingCheck = await billing.require({ plans: [MONTHLY_PLAN], onFailure: async () => billing.request({ plan: MONTHLY_PLAN }), }); const subscription = billingCheck.appSubscriptions[0]; const cancelledSubscription = await billing.cancel({ subscriptionId: subscription.id, isTest: true, prorate: true, }); // App logic }; ``` ##### shopify.server.ts ```typescript import { shopifyApp, BillingInterval } from "@shopify/shopify-app-remix/server"; export const MONTHLY_PLAN = 'Monthly subscription'; export const ANNUAL_PLAN = 'Annual subscription'; const shopify = shopifyApp({ // ...etc billing: { [MONTHLY_PLAN]: { amount: 5, currencyCode: 'USD', interval: BillingInterval.Every30Days, }, [ANNUAL_PLAN]: { amount: 50, currencyCode: 'USD', interval: BillingInterval.Annual, }, } }); export default shopify; export const authenticate = shopify.authenticate; ``` ## Related [Interact with the Admin API. - API context](https://shopify.dev/docs/api/shopify-app-remix/apis/admin-api) [Bill merchants for your app using the Admin API. - Billing context](https://shopify.dev/docs/api/shopify-app-remix/apis/billing)