Apple Login In Next Js Typescript
Tags: webdev, nextjs, javascript, oauth
Published: 2024-06-20 10:58:27

**_To integrate Apple Sign-In in a Next.js app with TypeScript, you need to follow a structured approach involving setting up Apple Sign-In in your Apple Developer account, implementing server-side authentication, and handling the client-side login flow._**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0liv434z8obrbhw9zwbx.png)

Here's a comprehensive guide to add Apple Sign-In to your Next.js TypeScript app:

**1.Set Up Apple Sign-In in [Apple Developer](https://developer.apple.com/) Account
Create an Apple Developer Account:**

1.Go to Apple Developer and log in or create an account.

2.Create an App ID:

Go to Certificates, Identifiers & Profiles.
Navigate to Identifiers and create a new App ID with the Sign in with Apple capability.

3. Generate a Service ID:

Create a new Service ID under Identifiers with the Sign in with Apple capability.

Configure the Return URLs with the callback URL you will use in your Next.js app (e.g., https://yourdomain.com/api/auth/apple/callback).

4. Create a Key:

Navigate to Keys and create a new key, enabling the Sign in with Apple capability.
Download the generated key file (.p8) as it will be used for JWT signing.

5. Configure Apple Sign-In:

Obtain the following credentials:

- Client ID: Your Service ID.
- Team ID: Your Apple Developer Team ID.
- Key ID: The ID of the key you created.
- Private Key: The contents of the .p8 file you downloaded.

**2.Server-Side: Implement Authentication in Next.js**
1. Install Dependencies:

```
npm install next-auth @auth/core axios jwt-decode

```
2. Create an API Route for Apple Sign-In:

Create a new file pages/api/auth/[...nextauth].ts:

```
// pages/api/auth/[...nextauth].ts
import NextAuth from 'next-auth';
import AppleProvider from 'next-auth/providers/apple';

export default NextAuth({
  providers: [
    AppleProvider({
      clientId: process.env.APPLE_CLIENT_ID!,
      clientSecret: {
        appleId: process.env.APPLE_CLIENT_ID!,
        teamId: process.env.APPLE_TEAM_ID!,
        privateKey: process.env.APPLE_PRIVATE_KEY!,
        keyId: process.env.APPLE_KEY_ID!,
        privateKeyId: process.env.APPLE_PRIVATE_KEY_ID!,
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  callbacks: {
    async jwt({ token, account }) {
      if (account) {
        token.accessToken = account.access_token;
      }
      return token;
    },
    async session({ session, token }) {
      session.accessToken = token.accessToken;
      return session;
    },
  },
});

```
Ensure you have the necessary environment variables set in your .env.local:

```
APPLE_CLIENT_ID=your_service_id
APPLE_TEAM_ID=your_team_id
APPLE_KEY_ID=your_key_id
APPLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----
NEXTAUTH_SECRET=your_next_auth_secret

```
3.Create JWT Generator for Apple Client Secret:

In your Next.js project, create a helper file lib/apple-jwt.ts:

```
// lib/apple-jwt.ts
import jwt from 'jsonwebtoken';

export const generateClientSecret = () => {
  const payload = {
    iss: process.env.APPLE_TEAM_ID,
    iat: Math.floor(Date.now() / 1000),
    exp: Math.floor(Date.now() / 1000) + 3600, // 1 hour expiration
    aud: 'https://appleid.apple.com',
    sub: process.env.APPLE_CLIENT_ID,
  };

  const options = {
    algorithm: 'ES256',
    header: {
      kid: process.env.APPLE_KEY_ID,
      typ: 'JWT',
    },
  };

  return jwt.sign(payload, process.env.APPLE_PRIVATE_KEY!, options);
};

```
4.Ensure the .p8 Private Key is Correctly Formatted:

Make sure your .p8 private key is correctly formatted with newline characters. You might need to replace actual newline characters with \n.

**3. Client-Side: Handle Apple Sign-In Button**

1.Install the Apple Sign-In Button:

```
npm install react-apple-signin-auth

```
2.Implement the Apple Sign-In Button:

Create a component for the Apple Sign-In button:

```
// components/AppleSignInButton.tsx
import React from 'react';
import AppleSignin from 'react-apple-signin-auth';
import { signIn } from 'next-auth/react';

const AppleSignInButton: React.FC = () => {
  return (
    <AppleSignin
      authOptions={{
        clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID!,
        scope: 'name email',
        redirectURI: `${window.location.origin}/api/auth/callback/apple`,
        state: 'state',
        nonce: 'nonce',
        usePopup: true,
      }}
      onSuccess={(response) => {
        console.log('Apple SignIn Success', response);
      }}
      onError={(error) => {
        console.error('Apple SignIn Error', error);
      }}
      render={(props) => (
        <button onClick={props.onClick} disabled={props.disabled}>
          Sign in with Apple
        </button>
      )}
    />
  );
};

export default AppleSignInButton;

```
3.Use the Apple Sign-In Button in Your App:

In your page or component where you want to include the Apple Sign-In:

```
// pages/index.tsx
import AppleSignInButton from '../components/AppleSignInButton';

const HomePage: React.FC = () => {
  return (
    <div>
      <h1>Sign in</h1>
      <AppleSignInButton />
    </div>
  );
};

export default HomePage;

```
4. Environment Configuration

Ensure you have these environment variables set up in .env.local:

```
NEXT_PUBLIC_APPLE_CLIENT_ID=your_service_id
APPLE_TEAM_ID=your_team_id
APPLE_KEY_ID=your_key_id
APPLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----
NEXTAUTH_SECRET=your_next_auth_secret

```

5. Testing
 1.Run Your App:
 
  

```
npm run dev

```

2.Navigate to Your Sign-In Page and test the Apple Sign-In flow.

**_Troubleshooting_**

- **Ensure Redirect URI Matches:** The redirect URI in your Apple Developer configuration must match the one used in your app.

- **Verify JWT: **Make sure the JWT signing configuration is correct, and you have properly formatted your private key.

- **Console Errors:** Check the browser console and network tab for any errors during the sign-in process for more debugging information.

> This should set up Apple Sign-In in your Next.js TypeScript app. Make sure to test thoroughly and handle any specific requirements for your application.