Skip to main content

methods/apple/server

The apple sign-in method, exported at @convex-dev/auth/methods/apple/server.

Type Aliases​

AppleOptions​

type AppleOptions = object;

App-defined config for setting up the apple method.

Properties​

PropertyTypeDescription
allowedRedirectOriginsstring[]Origins redirectTo may point at, e.g. ["https://app.example.com"] for open-redirect prevention.
componentComponentApiThe Apple oauth component instance, i.e. components.authApple.

AppleProfile​

type AppleProfile = Infer<typeof vAppleProfile>;

SanitizedAppleUser​

type SanitizedAppleUser = object;

Only the name parts are returned after sanitizing.

Properties​

PropertyType
nameobject
name.firstName?string
name.lastName?string

Variables​

vAppleProfile​

const vAppleProfile: VObject<{
email?: string;
emailVerified: boolean;
id: string;
name?: string;
}, {
email: VString<string | undefined, "optional">;
emailVerified: VBoolean<boolean, "required">;
id: VString<string, "required">;
name: VString<string | undefined, "optional">;
}, "required", "id" | "email" | "name" | "emailVerified">;

The account profile that the apple method produces. Apple is OIDC, so identity comes from validated id_token claims, with the name (when there is one) coming from the callback instead. This is the exact shape the mapping emits, so the app can validate against it precisely.

Functions​

normalizeAppleProfile()​

function normalizeAppleProfile(claims, user): object;

Map Apple's validated id_token claims, plus the sanitized name from a first authorization, to AppleProfile.

user is undefined on every sign-in after the first, which is why the profile's name is optional. An app that wants to keep the name should store it when it arrives and leave the stored one alone when it doesn't.

Parameters​

ParameterType
claimsOidcClaims
userSanitizedAppleUser | undefined

Returns​

object

email?​
optional email?: string;
emailVerified​
emailVerified: boolean;
id​
id: string;
name?​
optional name?: string;

setupApple()​

function setupApple<UsersTable>(core, options): object;

Built-in sign-in method for Apple ("Sign in with Apple"). Wire it up with the Apple oauth component:

const auth = setupConvexAuth({ component: components.auth });
export const { signOut, refreshSession, isAuthenticated } = auth;

export const { startSignInWithApple, completeSignInWithApple } = setupApple(auth, {
component: components.authApple,
allowedRedirectOrigins: ["https://app.example.com", "http://localhost:5173"],
}).attachUserCallbacks({ createUser: internal.users.createUserApple });

Setup:

  1. Install the component in convex.config.ts under httpPrefix: "/oauth/apple", binding the Services ID, team id, key id, and .p8 private key.
  2. Register <site-url>/oauth/apple/callback as a return URL on the Services ID, along with the convex.site domain it is on.

The httpPrefix alone determines the callback URL, on the deployment's convex.site host. Apple has to accept that host as a return URL and rejects localhost and IP addresses, so the deployment has to be publicly reachable. The app the flow returns to is unaffected and can stay on localhost.

Type Parameters​

Type Parameter
UsersTable extends string

Parameters​

ParameterType
coreAuthCore<UsersTable>
optionsAppleOptions

Returns​

attachUserCallbacks()​
attachUserCallbacks(callbacks): object;

Supply the app's user callbacks (see UserCallbacks for how their args must be declared) and get the functions of this method to export.

Parameters​
ParameterType
callbacksUserCallbacks<"apple", { email?: string; emailVerified: boolean; id: string; name?: string; }, UsersTable>
Returns​

object

completeSignInWithApple​
completeSignInWithApple: RegisteredMutation<"public", {
code: string;
state: string;
}, Promise<
| {
status: "complete";
tokens: {
accessToken: string;
refreshToken: string;
refreshTokenExpiresAt: number;
userId: string;
};
}
| {
status: "error";
userError: {
error: "INVALID_CODE";
};
}>> = completeSignIn;
startSignInWithApple​
startSignInWithApple: RegisteredMutation<"public", {
redirectTo: string;
}, Promise<{
redirect: string;
state: string;
}>> = startSignIn;