API reference
withBlueprintAuth
This is a next.config.js webpack
config wrapper to fix 'No QueryClient set, use QueryClientProvider to set one' issue with @tanstack/react-query
when imported in server-side code:
Import
import { withBlueprintAuth } from '@krakentech/blueprint-auth';
Usage
In your Next.js next.config.js
file:
const withBlueprintAuth = require('@krakentech/blueprint-auth');
module.exports = {
(...)
webpack: (config, context) => {
(...)
return withBlueprintAuth({ config, context });
},
};
AuthProvider
Provides context to auth hooks.
Import
import { AuthProvider } from '@krakentech/blueprint-auth';
Usage
In your Next.js _app.tsx
file:
import { AuthProvider } from '@krakentech/blueprint-auth';
function App({ Component, pageProps }) {
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
}
export default App;
This is a very basic example. You probably have other providers in your
_app.tsx
file, make sure you wrap the ones that need to use the auth hooks with theAuthProvider
.
authMiddleware
This function is meant to be used in a Next.js middleware function:
- It will check if the user is authenticated and has the necessary tokens to access the requested protected route.
- If the user is not authenticated, it will redirect them to the login page.
- If the user is authenticated, it will check if the access token is still valid and refresh it if necessary.
The
krakenConfig.xClientIpSecrectKey
is used as the value of thex-client-ip-authorization
header. This header is used by Kraken to prevent valid server-side requests, which originate from a single/pool of IPs (this will be the case if you host your app in Vercel for example), from being erroneously rate-limited. More information can be found on this Kraken announcement.
Import
import { authMiddleware } from '@krakentech/blueprint-auth';
We expose this function separately to avoid bundling code that is unsupported in Edge Runtime. Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation
Usage
In your Next.js middleware.ts
file:
import { NextResponse, type NextRequest } from 'next/server';
import { authMiddleware } from '@krakentech/blueprint-auth';
export const config = {
matcher: [
'/anon/:path*',
'/dashboard/:path*',
'/login',
'/masquerade/:path*',
],
};
export async function middleware(req: NextRequest) {
const res = NextResponse;
return await authMiddleware({
req,
res,
krakenConfig: {
graphqlEndpoint: process.env.KRAKEN_GRAPHQL_ENDPOINT,
xClientIpSecretKey: process.env.KRAKEN_X_CLIENT_IP_SECRET_KEY,
},
appRoutes: {
anon: {
path: '/anon',
getPreSignedKey: (url) => {
const [_anon, preSignedKey] = url.pathname
.split('/')
.filter(Boolean);
return { preSignedKey };
},
},
dashboard: {
path: '/dashboard',
},
login: {
path: '/login',
},
masquerade: {
path: '/masquerade',
getUserIdAndMasqueradeToken: (url) => {
const [_masquerade, userId, masqueradeToken] = url.pathname
.split('/')
.filter(Boolean);
return { userId, masqueradeToken };
},
},
},
setCustomHeaders: (headers) => {
headers.set(name, value);
},
useSecureCookie: !process.env.NODE_ENV === 'test',
});
}
loginHandler
Handles the login process. This function must be used in a Next.js API route:
- It first checks if the request method is
POST
, if not, it returns405
response. - Then it creates a new
Headers
object, optionally including any custom headers passed in. - If the request is successful, it sets the necessary auth cookies necessary and returns a
200
response with a standardised JSON object. - If the request fails, it returns a
400
response with a standardised JSON object.
Import
import { loginHandler } from '@krakentech/blueprint-auth';
Usage
In your Next.js login api route:
import type { NextApiRequest, NextApiResponse } from 'next';
import { loginHandler } from '@krakentech/blueprint-auth';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
await loginHandler({
req,
res,
krakenConfig: {
graphqlEndpoint: process.env.KRAKEN_GRAPHQL_ENDPOINT,
xClientIpSecretKey: process.env.KRAKEN_X_CLIENT_IP_SECRET_KEY,
},
setCustomHeaders: (headers) => {
headers.set(name, value);
},
useSecureCookie: !process.env.NODE_ENV === 'test',
});
}
logoutHandler
Handles the logout process. This function must be used in a Next.js API route:
- It first checks if the request method is
GET
, if not, it returns405
response. - Then it removes every auth related cookie and returns a
200
response with theCache-Control
header set and a standardised JSON object.
Import
import { logoutHandler } from '@krakentech/blueprint-auth';
Usage
In your Next.js logout api route:
import type { NextApiRequest, NextApiResponse } from 'next';
import { logoutHandler } from '@krakentech/blueprint-auth';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
logoutHandler({
req,
res,
});
}
sessionHandler
Handles the session state. This function must be used in a Next.js API route:
- It first checks if the request method is
GET
, if not, it returns405
response. - Then asserts the current auth state of the user by retrieving the auth related cookies.
- The
isAuthenticated
value is derived from the presence of either:- both 'access' and 'refresh' cookies
- a 'masquerade' cookie
- The
isMasquerading
value is derived from the presence of a 'masquerade' cookie. - The
sub
state is derived from the presence of a 'sub' cookie.
- The
- Then returns a
200
response with theCache-Control
header set to prevent caching and a JSON object with the derived state.
Import
import { sessionHandler } from '@krakentech/blueprint-auth';
Usage
In your Next.js session api route:
import type { NextApiRequest, NextApiResponse } from 'next';
import { sessionHandler } from '@krakentech/blueprint-auth';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
sessionHandler({
req,
res,
});
}
graphqlHandler
Handles every Kraken GraphQL request. This function must be used in a Next.js API route:
- It first checks if the request method is
POST
, if not, it returns405
response. - Then it creates a new
Headers
object, optionally including any custom headers passed in. - If the request is successful, it returns a
200
response with the data object. - If the request fails, it returns a
200
response with the error object. - If the request fails due to a
ACCESS TOKEN EXPIRED
error, it will attempt to refresh the access token and retry the request. - If the request fails due to other auth related errors, it will remove the auth cookies and return the error.
If you intend to make organization scoped requests (either by using the getGraphQLClient
helper with it's scope
prop set to organization
or by using the organizationScopedGraphQLClient
returned by the useGraphQLClients
hook) you need to pass a few additional props:
krakenConfig.organizationSecretKey
: the secret key of the organization.encryption
: an object with thekey
andiv
values used to encrypt theorganization
token. We use these to encrypt/decrypt theorganization
token. This is to prevent the token from being exposed to the client as this is a sensitive and unique value issued by Kraken and a bad actor could potentially use it to make organization scoped authenticated queries/mutations. Both thekey
andiv
must be at least 12 characters long. One possible way of generating them is by using the following command:openssl rand -base64 12
. We recommend storing these values in your environment variables. Both of them should be rotated periodically.edgeConfig
: an object with theenvVar
,teamId
andauthToken
values. We are storing the encryptedorganization
token in the Vercel Edge Config Store connected to you Vercel project, which means that you need to set one up. You can do that at the following URL:https://vercel.com/<team-id>/<your-project-name>/stores
. Once you create one, Vercel will automatically create anEDGE_CONFIG
environment variable for you. This is the value that you need to pass to theedgeConfig.envVar
prop. Its value should look like this:https://edge-config.vercel.com/<edge-config-store-id>?token=<auth-token>
. You'll also have to create an access token so that you can interact with the store.
If you try to make an organization scoped request without passing these props, the request will fail with errors stating that they are missing. Basically, if you see any of the following errors, it means that you need to pass the missing props to the graphqlHandler
function:
- blueprint-auth: getOrganizationAccessToken — krakenConfig.organizationSecretKey is required.
- blueprint-auth: createOrganizationTokenUtils — edgeConfig.envVar, edgeConfig.teamId, and edgeConfig.authToken are required.
- blueprint-auth: createEncryptionUtils — encryption.key and encryption.iv are required. Bear in mind that their values should have at least 12 characters. One possible way of generating them is by using the following command: openssl rand -base64 12.
If you want to prevent mutations from being executed in dev mode whenever devs are pointing to a production api, you can set the
preventMutationsOnProdApiWhileInDev
prop totrue
.
Import
import { graphqlHandler } from '@krakentech/blueprint-auth';
Usage
In your Next.js graphql api route:
import type { NextApiRequest, NextApiResponse } from 'next';
import { graphqlHandler } from '@krakentech/blueprint-auth';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
await graphqlHandler({
req,
res,
krakenConfig: {
graphqlEndpoint: process.env.KRAKEN_GRAPHQL_ENDPOINT,
organizationSecretKey: process.env.KRAKEN_ORGANIZATION_KEY,
xClientIpSecretKey: process.env.KRAKEN_X_CLIENT_IP_SECRET_KEY,
},
setCustomHeaders: (headers) => {
headers.set(name, value);
},
useSecureCookie: !process.env.NODE_ENV === 'test',
shouldValidateUrl: !process.env.NODE_ENV === 'test',
encryption: {
key: process.env.AUTH_ENCRYPTION_KEY,
iv: process.env.AUTH_ENCRYPTION_IV,
},
edgeConfig: {
envVar: process.env.EDGE_CONFIG,
teamId: process.env.VERCEL_TEAM_ID,
authToken: process.env.VERCEL_AUTH_TOKEN,
},
});
}
krakenOAuthHandler
Handles the OAuth process. This function must be used in a Next.js API route:
Import
import { krakenOAuthHandler } from '@krakentech/blueprint-auth';
Usage
In your Next.js OAuth api route:
import type { NextApiRequest, NextApiResponse } from 'next';
import { krakenOAuthHandler } from '@krakentech/blueprint-auth';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
await krakenOAuthHandler({
req,
res,
krakenConfig: {
authEndpoint: process.env.KRAKEN_AUTH_ENDPOINT,
clientId: process.env.KRAKEN_CLIENT_ID,
clientSecret: process.env.KRAKEN_CLIENT_SECRET,
},
appRoutes: {
login: '/login',
logout: '/logout',
krakenOAuth: '/api/auth/kraken-oauth',
},
});
}
updateOrgTokenHandler
Handles the update organization token request. This is meant to be a cron job and must be used in a Next.js API route:
- It first checks if the request is authorized by checking if the authorization header matches the
CRON_SECRET
environment variable. The secret can be any string value. - Then it updates the organization token.
- If both the request to get the token and write the token to the edge config are successful, it returns a
200
response with the data object. - If the request fails, it returns a
200
response with the error object.
You will also have to configure the api route where you use this handler to be a cron job in Vercel.
You can do that by creating a vercel.json
file at the root of your project with the following content:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [
{
"path": "/api/auth/update-org-token",
"schedule": "*/55 * * * *"
}
]
}
Set the
schedule
value to the desired cron job schedule. The example above will run the cron job every 55 minutes. (usually, the organization token expires every hour)
Import
import { updateOrgTokenHandler } from '@krakentech/blueprint-auth';
Usage
In your Next.js update organization token api route:
import type { NextApiRequest, NextApiResponse } from 'next';
import { updateOrgTokenHandler } from '@krakentech/blueprint-auth';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
await updateOrgTokenHandler({
req,
res,
krakenConfig: {
graphqlEndpoint: process.env.KRAKEN_GRAPHQL_ENDPOINT,
organizationSecretKey: process.env.KRAKEN_ORGANIZATION_KEY,
xClientIpSecretKey: process.env.KRAKEN_X_CLIENT_IP_SECRET_KEY,
},
encryption: {
key: process.env.AUTH_ENCRYPTION_KEY,
iv: process.env.AUTH_ENCRYPTION_IV,
},
edgeConfig: {
envVar: process.env.EDGE_CONFIG,
teamId: process.env.VERCEL_TEAM_ID,
authToken: process.env.VERCEL_AUTH_TOKEN,
},
});
}
createKrakenOAuthURI
Creates the Kraken OAuth URI.
Import
import { createKrakenOAuthURI } from '@krakentech/blueprint-auth';
Usage
In your Next.js page where you want to redirect the user to the Kraken OAuth page. This URI should be used in a button or link to redirect the user to the Kraken OAuth page.
import { createKrakenOAuthURI } from '@krakentech/blueprint-auth';
...
export const getServerSideProps: GetServerSideProps = async (context) => {
const { req, res } = context;
const authorizeURI = await createKrakenOAuthURI({
req,
res,
krakenConfig: {
authEndpoint: process.env.KRAKEN_AUTH_ENDPOINT as string,
oauthClientId: process.env.KRAKEN_OAUTH_CLIENT_ID as string,
},
krakenOAuthApiRoute: '/api/auth/kraken-oauth',
});
return {
props: {
authorizeURI,
},
};
};
useLogin
Hook that provides a function to login a user.
Import
import { useLogin } from '@krakentech/blueprint-auth';
Usage
In your component:
import { useLogin } from '@krakentech/blueprint-auth';
const LoginButton = ({ email, password }) => {
const { mutate } = useLogin();
return <button onClick={() => mutate({ email, password })}>Login</button>;
};
useLogout
Hook that provides a function to logout a user.
Import
import { useLogout } from '@krakentech/blueprint-auth';
Usage
In your component:
import { useLogout } from '@krakentech/blueprint-auth';
const LogoutButton = () => {
const { mutate } = useLogout();
return <button onClick={() => mutate()}>Logout</button>;
};
useSession
Hook that provides the current auth session data. Bear in mind that this "@tanstack/react-query"
hook has all refetch properties set to true
( refetchOnMount
, refetchOnWindowFocus
and refetchOnReconnect
) which means that you should see quite a few requests being made to the session endpoint, especially if you keep refocusing the window when using the browser's developer tools.
Import
import { useSession } from '@krakentech/blueprint-auth';
Usage
In your component:
import { useSession } from '@krakentech/blueprint-auth';
const Page = () => {
const {
isInitialLoading,
isAuthenticated,
isMasquerading,
sub,
invalidateSessionCache,
} = useSession();
if (isInitialLoading) {
return <p>Loading...</p>;
}
return (
<div>
<p>Authenticated: {isAuthenticated ? 'Yes' : 'No'}</p>
<p>Masquerading: {isMasquerading ? 'Yes' : 'No'}</p>
<p>Sub: {sub}</p>
<button onClick={() => invalidateSessionCache()}>
Invalidate session
</button>
</div>
);
};
prefetchSession
This function is used to prefetch the session data. It's useful when you want to prefetch the session data on the server-side.
Import
import { prefetchSession } from '@krakentech/blueprint-auth';
Usage
In your Next.js page:
import { QueryClient } from '@tanstack/react-query';
import { prefetchSession } from '@krakentech/blueprint-auth';
export const getServerSideProps: GetServerSideProps = async (context) => {
const queryClient = new QueryClient();
await prefetchSession({
queryClient,
context,
});
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
};
getSessionData
This function is used to get the session data. It's useful when you want to get the session data on the server-side.
Import
import { getSessionData } from '@krakentech/blueprint-auth';
Usage
In your Next.js page:
import { getSessionData } from '@krakentech/blueprint-auth';
export const getServerSideProps: GetServerSideProps = async (context) => {
const sessionData = await getSessionData({
req: context.req,
res: context.res,
});
return {
props: {...},
};
};
useKrakenAuthErrorHandler
There are two methods available in this hook:
getAuthErrorCode(e: unknown)
- this method returns theerrorCode
based on theerrorType
(such as 'UNAUTHORIZED', 'AUTH_HEADER_NOT_PROVIDED', etc) from the server response.handleKrakenErrors(onError?: (e: unknown) => void))
- this method can be used in theerrorCallback
prop in the Blueprint hooks and in other places where you need to handle the authentication related errors. It will check the error code and either call the custom onError function if provided, or redirect the user to the login page with the current page as the next page and the error code as a query parameter
Import
import { useKrakenAuthErrorHandler } from '@krakentech/blueprint-auth';
Usage
In your component:
import { useKrakenAuthErrorHandler } from "@krakentech/blueprint-auth";
...
// Check the error code using the error received from the server. If it's authentication related error, you will get the error code.
const { getAuthErrorCode } = useKrakenAuthErrorHandler();
...
const errorCode = getAuthErrorCode({ response: { errors: error.graphQLErrors }});
if (errorCode) {
//Do something
}
// Pass it in the errorCallback in the Blueprint hooks. Example with useMeasurements hook below
const { handleKrakenErrors } = useKrakenAuthErrorHandler();
...
const measurements = useMeasurements({
variables: {
accountNumber,
propertyId,
utilityType,
dateLocale: config.i18n.dateLocales[locale || ''],
marketSupplyPointId: prm.id,
enabled: true,
startAt: STATS_START_AT,
endAt: STATS_ANCHOR_DATE,
first: 14,
dateRange: DateRangeToggleValue.WEEK,
},
errorCallback: handleKrakenErrors,
locale,
});
useGraphQLClients
This hook returns an object with two GraphQL clients: one scoped to the user and the other to the organization (organization scope deprecated - see getServerSideGraphQLClients
).
Import
import { useGraphQLClients } from '@krakentech/blueprint-auth';
Usage
In a custom react query hook, for example:
import { useMutation } from 'react-query';
import { getGraphQLClient } from '@krakentech/blueprint-auth';
const UpdatePassword = gql`
mutation UpdatePassword($input: UpdatePasswordInput!) {
updatePassword(input: $input) {
viewer {
givenName
familyName
mobile
email
}
}
}
`;
export const useCreateAccount = (input: UpdatePasswordInput) => {
const { userScopedGraphQLClient } = useGraphQLClients();
return useMutation({
mutationFn: async () => {
return userScopedGraphQLClient.request(UpdatePassword, {
input,
});
},
});
};
import { useMutation } from 'react-query';
import { getGraphQLClient } from '@krakentech/blueprint-auth';
const CreateAccountMutation = graphql(`
mutation CreateAccount($input: CreateAccountInput!) {
createAccount(input: $input) {
accountNumber
token
userId
}
}
`);
export const useCreateAccount = (input: CreateAccountInput) => {
// @deprecated - create a custom API route using getServerSideGraphQLClients
// for organisation scoped requests
const { organizationScopedGraphQLClient } = useGraphQLClients();
return useMutation({
mutationFn: async () => {
return organizationScopedGraphQLClient.request(
CreateAccountMutation,
{
input,
}
);
},
});
};
getServerSideGraphQLClients
This helper function returns GraphQL clients scoped to either the user or the organization to make it easier for you to make authenticated GraphQL requests.
It's meant to be used in Next.js Node.js and Edge Runtime environments, in particular getServerSideProps
, getStaticProps
, API handlers of the pages router, but also in the middleware, and in route handlers of the app router.
⚠️ The current implementation is not compatible with server-components.
This function returns an object containing both organizationScopedGraphQLClient
and userScopedGraphQLClient
GraphQL clients. They can be used to make authenticated requests directly to the Kraken API by providing the appropriate credentials and API URL.
Note: if you enabled Vercel's deployment protection, you will have to also enable the "Protection Bypass for Automation" so that requests that use either of these functions can be made successfully in preview deployments as well.

CAVEAT - Requests made with
userScopedGraphQLClient
ingetStaticProps
won't be authenticated. This is becausegetStaticProps
runs at build time and doesn't have access to the session's cookies.
Import
import { getServerSideGraphQLClients } from '@krakentech/blueprint-auth';
Usage
In your Next.js page:
import { getServerSideGraphQLClients } from '@krakentech/blueprint-auth';
...
const ViewerQuery = gql`
query Viewer {
viewer {
preferredName
email
accounts {
number
}
}
}
`;
const CreateAccountMutation = gql`
mutation CreateAccount($input: CreateAccountInput!) {
createAccount(input: $input) {
accountNumber
token
userId
}
}
`;
export const getServerSideProps: GetServerSideProps = async (context) => {
const { userScopedGraphQLClient, organizationScopedGraphQLClient } = getServerSideGraphQLClients({
krakenGraphqlApiUrl: 'https://api.clientcode-kraken.energy/v1/graphql/',
context,
config,
});
const { viewer } = await userScopedGraphQLClient.request(ViewerQuery);
const { createAccount } = await organizationScopedGraphQLClient.request(CreateAccountMutation, {
input: {
...
},
});
return {
props: {
...,
},
};
};
Name | Description | Type |
---|---|---|
krakenGraphqlApiUrl | The URL of the Kraken GraphQL API URL. ⚠️ You MUST provide the full path (including the protocol), and don't forget the trailing slash. Example https://api.clientcode-kraken.energy/v1/graphql/ | string |
context | The context object from Next.js, either GetServerSidePropsContext or GetStaticPropsContext , or an object containing the request and response { req: Request | NextRequest, res: Response | NextResponse } | GetServerSidePropsContext | GetStaticPropsContext | { req: Request | NextRequest, res: Response | NextResponse } |
config | Various Kraken environment variables - full description below | GetServerSideCliensGraphQLConfigOptions (optional) |
Example config object
The values here are the defaults set by Blueprint - if you set these values in your env file they will get picked up automatically, or you can pass them in explicitly.
const config: GetServerSideCliensGraphQLConfigOptions = {
krakenConfig: {
// the secret key for the organisation you want to authenticate as
organizationSecretKey: process.env.KRAKEN_ORGANIZATION_KEY,
// the secret key used for your kraken to override the ip address for requests for rate limiting purposes
xClientIpSecretKey: process.env.KRAKEN_X_CLIENT_IP_SECRET_KEY,
// a value to use to override the x-client-ip address passed to Kraken.
// This is useful if your build process or e2e tests are getting rate limited by a localhost ip address.
xClientIpOverride: '',
},
edgeConfig: {
// edge config string for the project, used for caching encrypted org tokens
envVar: process.env.EDGE_CONFIG,
// vercel team id
teamId: process.env.VERCEL_TEAM_ID,
// vercel auth token
authToken: process.env.VERCEL_AUTH_TOKEN,
},
encryption: {
// the encryption key used to encrypt the cached org tokens
key: process.env.AUTH_ENCRYPTION_KEY,
// the IV used to encrypt the cached org tokens
iv: process.env.AUTH_ENCRYPTION_IV,
},
// callback to modify the default request headers (optional)
setCustomHeaders: null,
// set to false to disable secure cookies, e.g. in tests
useSecureCookie: true;
};
Examples
All examples below showcase the organizationScopedGraphQLClient
, but the userScopedGraphQLClient
GraphQL client shares the same API.
- Page server-side rendering (pages router)
const thirdPartyViewerQuery = gql`
query {
thirdPartyViewer {
name
}
}
`;
const Page = ({ thirdPartyViewer }: InferGetServerSidePropsType<typeof getServerSideProps>) => {
return (
<Stack direction="vertical" gap="sm">
<Typography>
Third Party Viewer: {thirdPartyViewer.name}{' '}
<i>(org scoped request)</i>
</Typography>
</Stack>
);
};
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
const { organizationScopedGraphQLClient } = getServerSideGraphQLClients({
krakenGraphqlApiUrl: 'https://api.clientcode-kraken.energy/v1/graphql/',
context,
});
const { thirdPartyViewer } = await organizationScopedGraphQLClient.request(thirdPartyViewerQuery);
return { props: { thirdPartyViewer } };
};
- API handler (pages router)
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { organizationScopedGraphQLClient } = getServerSideGraphQLClients({
krakenGraphqlApiUrl: 'https://api.clientcode-kraken.energy/v1/graphql/',
context: { req, res },
});
const { thirdPartyViewer } = await organizationScopedGraphQLClient.request(thirdPartyViewerQuery);
return res.json(thirdPartyViewer);
};
- Route handler (app router)
export async function GET(req: NextRequest) {
const res = new NextResponse();
const { organizationScopedGraphQLClient } = getServerSideGraphQLClients({
krakenGraphqlApiUrl: 'https://api.clientcode-kraken.energy/v1/graphql/',
context: { req, res },
});
const { thirdPartyViewer } = await organizationScopedGraphQLClient.request(thirdPartyViewerQuery);
return NextResponse.json(thirdPartyViewer, res);
};
- Next.js middleware (pages and app router)
export async function middleware(req: NextRequest) {
const res = NextResponse.next();
const { organizationScopedGraphQLClient } = getServerSideGraphQLClients({
krakenGraphqlApiUrl: 'https://api.clientcode-kraken.energy/v1/graphql/',
context: { req, res }
})
const { thirdPartyViewer } = await organizationScopedGraphQLClient.request(thirdPartyViewerQuery);
// do something with the request result
};
Rate limiting
If you find your build processes or automated tests are being incorrectly rate limited on your organisation requests
because the IP being used to rate limit is something like 1.1.1.1, you can set an x-client-ip header to be used to rate limit against.
You'll need to set xClientIpSecretKey
and xClientIpOverride
in your client config.
Tips
- Convenience wrapper
Configuring the GraphQL client in every server-rendered page and API endpoint can redundant and error prone, in particular if you consistently need to set configuration options.
You could create a convenience wrapper around getServerSideGraphQLClients
for easy reuse.
// src/lib/blueprint-auth/server.ts
import {
getServerSideGraphQLClients,
GetServerSideGraphQLClientArgs,
} from '@krakentech/blueprint-auth';
export function getGraphQLClients({
context,
}: Pick<GetServerSideGraphQLClientArgs, 'context'>) {
return getServerSideGraphQLClients({
krakenGraphqlApiUrl: process.env.KRAKEN_GRAPHQL_ENDPOINT || '',
context,
config: {
setCustomHeaders(headers) {
headers.set('x-custom-header', process.env.MY_CUSTOM_HEADER);
},
useSecureCookie: process.env.NODE_ENV === 'test',
},
});
};
- Alternative object config
The request
method of the AuthenticatedGraphQLClient
class uses the same API as request
method from the GraphQLClient
class from graphql-client
.
It is therefore compatible with the alternative object config:
const { account } = await userScopedGraphQLClient.request(
accountQuery,
{ accountNumber: context.query.accuntNumber },
);
const { account } = await userScopedGraphQLClient.request({
document: accountQuery,
variables: { accountNumber: context.query.accuntNumber },
});
- Request-level headers
The setCustomHeaders
config allows setting custom headers at the client level, meaning all requests made with the same client instance will share these headers.
If you need to set headers for a particular request, you can provide them to the request
method:
const { account } = await userScopedGraphQLClient.request(
accountQuery,
{ accountNumber: context.query.accuntNumber },
{ 'x-custom-header': 'MY_CUSTOM_HEADER' },
);
Alternatively, using the object config, which can be convenient for queries without variables:
const { viewer } = await userScopedGraphQLClient.request({
document: viewerQuery,
requestHeaders: { 'x-custom-header': 'MY_CUSTOM_HEADER' },
});
- Abort requests with AbortController
In case you need to abort a request, you can pass an AbortSignal
instance using the alternative object config:
const abortController = new AbortController();
const { viewer } = await userScopedGraphQLClient.request({
document: viewerQuery,
signal: abortController.signal,
});
// somewhere else in your code
abortController.abort();
setNextPageSearchParam
This function sets the nextPage
search param in the URL. This is the search param that we are setting in the authMiddleware
function when we redirect the user to the login page.
Import
import { setNextPageSearchParam } from '@krakentech/blueprint-auth';
Usage
import { setNextPageSearchParam } from '@krakentech/blueprint-auth';
const url = new URL(...);
const nextUrl: NextUrl = ...;
setNextPageSearchParam({ url, nextUrl });
redirectToNextPage
This function redirects the user to the nextPage
search param in the URL. It sanitizes the URL to prevent XSS attacks by checking if the URL is either a relative or an absolute path.
Import
import { redirectToNextPage } from '@krakentech/blueprint-auth';
Usage
In your Next.js page:
import { redirectToNextPage } from '@krakentech/blueprint-auth';
...
const Page = () => {
const router = useRouter();
useEffect(() => {
redirectToNextPage({
router,
defaultPath: '/dashboard',
});
}, []);
return <p>Redirecting...</p>;
};