{"id":29182912,"url":"https://github.com/magiclabs/example-nextjs","last_synced_at":"2025-09-10T21:34:04.347Z","repository":{"id":43373883,"uuid":"285635423","full_name":"magiclabs/example-nextjs","owner":"magiclabs","description":null,"archived":false,"fork":false,"pushed_at":"2023-03-05T13:38:10.000Z","size":1107,"stargazers_count":98,"open_issues_count":10,"forks_count":42,"subscribers_count":12,"default_branch":"master","last_synced_at":"2023-03-06T02:38:17.798Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/magiclabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-08-06T17:50:33.000Z","updated_at":"2023-03-06T02:38:17.798Z","dependencies_parsed_at":"2023-02-06T05:30:43.500Z","dependency_job_id":null,"html_url":"https://github.com/magiclabs/example-nextjs","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"purl":"pkg:github/magiclabs/example-nextjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-nextjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-nextjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-nextjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-nextjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/magiclabs","download_url":"https://codeload.github.com/magiclabs/example-nextjs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclabs%2Fexample-nextjs/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263033239,"owners_count":23403120,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-01T20:33:29.878Z","updated_at":"2025-07-01T20:33:30.628Z","avatar_url":"https://github.com/magiclabs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Demo\n\nLive at https://magic-nextjs.vercel.app/login\n\n# Quick Start Instructions\n\n```\n$ git clone https://github.com/magiclabs/example-nextjs\n$ cd example-nextjs\n$ mv .env.local.example .env.local // enter your Magic API keys in your env variables\n$ yarn install\n$ yarn dev // starts app in http://localhost:3000\n```\n\n## Environment Variables\n\n```\nNEXT_PUBLIC_MAGIC_PUBLISHABLE_KEY=pk_live_123...\nMAGIC_SECRET_KEY=sk_live_123...\n```\n\n# Introduction\n\nMagic is a passwordless authentication sdk that lets you plug and play different auth methods into your app. Magic supports passwordless email login via magic links, social login (such as Login with Google), and WebAuthn (a protocol that lets users authenticate a hardware device using either a YubiKey or fingerprint). This app will walk through implementing magic link and social logins.\n\n## File Structure\n\n```txt\n├── README.md\n├── components\n│   ├── email-form.js\n│   ├── header.js\n│   ├── layout.js\n│   ├── loading.js\n│   └── social-logins.js\n├── lib\n│   ├── UserContext.js\n│   └── magic.js\n├── package.json\n├── pages\n│   ├── _app.js\n│   ├── _document.js\n│   ├── api\n│   │   └── login.js\n│   ├── callback.js\n│   ├── index.js\n│   ├── login.js\n│   └── profile.js\n├── public\n│   └── (images)\n└── yarn.lock\n```\n\n## Magic Setup\n\nYour Magic setup will depend on what login options you want. For magic links, minimal setup is required. For social logins, follow our [**documentation**](https://docs.magic.link/social-login) for configuration instructions.\n\nOnce you have social logins configured (if applicable), grab your API keys from Magic’s dashboard and in `.env.local` enter your Test Publishable Key such as `NEXT_PUBLIC_MAGIC_PUBLISHABLE_KEY=pk_test_1234567890` and your Test Secret Key such as `MAGIC_SECRET_KEY=sk_test_1234567890`.\n\n# Client\n\n## Keeping Track of the User\n\nThis example app will keep track of the logged in user by using React's `useContext` hook. Inside `_app.js`, wrap the entire app in the `\u003cUserContext.Provider\u003e` so all child components down the component tree have access to see if the user is logged in or not (`UserContext` is exported from `lib/UserContext`). Once a user logs in with Magic, unless they log out, they'll remian logged in for 7 days until their session expires.\n\n```js\n// If isLoggedIn is true, set the UserContext with user data\n// Otherwise, redirect to /login and set UserContext to { user: null }\nuseEffect(() =\u003e {\n  setUser({ loading: true });\n  magic.user.isLoggedIn().then((isLoggedIn) =\u003e {\n    if (isLoggedIn) {\n      magic.user.getMetadata().then((userData) =\u003e setUser(userData));\n    } else {\n      Router.push('/login');\n      setUser({ user: null });\n    }\n  });\n}, []);\n\nreturn (\n  \u003cUserContext.Provider value={[user, setUser]}\u003e\n    \u003cLayout\u003e\n      \u003cComponent {...pageProps} /\u003e\n    \u003c/Layout\u003e\n  \u003c/UserContext.Provider\u003e\n);\n```\n\n## Magic Link Auth\n\nIn `pages/login.js`, handle `magic.auth.loginWithMagicLink()` which is what triggers the magic link to be emailed to the user. It takes an object with two parameters, `email` and an optional `redirectURI`. Magic allows you to configure the email link to open up a new tab, bringing the user back to your application. With the redirect in place, a user will get logged in on both the original and new tab. Once the user clicks the email link, send the `didToken` to the server endpoint at `/api/login` to validate it, and if the token is valid, set the `UserContext` and redirect to the profile page.\n\n```js\nasync function handleLoginWithEmail(email) {\n  // Trigger Magic link to be sent to user\n  let didToken = await magic.auth.loginWithMagicLink({\n    email,\n    redirectURI: new URL('/callback', window.location.origin).href, // optional redirect back to your app after magic link is clicked\n  });\n\n  // Validate didToken with server\n  const res = await fetch('/api/login', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      Authorization: 'Bearer ' + didToken,\n    },\n  });\n\n  if (res.status === 200) {\n    // Set the UserContext to the now logged in user\n    let userMetadata = await magic.user.getMetadata();\n    await setUser(userMetadata);\n    Router.push('/profile');\n  }\n}\n```\n\n## Social Logins\n\nThe social login implementation is similar. `magic.oauth.loginWithRedirect()` takes an object with a `provider`, and a required `redirectURI` for where to redirect back to once the user authenticates with the social provider and with Magic. In this case, the user will get redirected to `http://localhost:3000/callback`.\n\n```js\nfunction handleLoginWithSocial(provider) {\n  magic.oauth.loginWithRedirect({\n    provider, // google, apple, etc\n    redirectURI: new URL('/callback', window.location.origin).href, // required redirect to finish social login\n  });\n}\n```\n\n## Handling Redirect\n\nIn the `/callback` page, check if the query parameters include a `provider`, and if so, finish the social login, otherwise, it’s a user completing the email login.\n\n```js\n// The redirect contains a `provider` query param if the user is logging in with a social provider\nuseEffect(() =\u003e {\n  router.query.provider ? finishSocialLogin() : finishEmailRedirectLogin();\n}, [router.query]);\n\n// `getRedirectResult()` returns an object with user data from Magic and the social provider\nconst finishSocialLogin = async () =\u003e {\n  let result = await magic.oauth.getRedirectResult();\n  authenticateWithServer(result.magic.idToken);\n};\n\n// `loginWithCredential()` returns a didToken for the user logging in\nconst finishEmailRedirectLogin = () =\u003e {\n  if (router.query.magic_credential)\n    magic.auth.loginWithCredential().then((didToken) =\u003e authenticateWithServer(didToken));\n};\n\n// Send token to server to validate\nconst authenticateWithServer = async (didToken) =\u003e {\n  let res = await fetch('/api/login', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      Authorization: 'Bearer ' + didToken,\n    },\n  });\n\n  if (res.status === 200) {\n    // Set the UserContext to the now logged in user\n    let userMetadata = await magic.user.getMetadata();\n    await setUser(userMetadata);\n    Router.push('/profile');\n  }\n};\n```\n\n## Logout\n\nUsers also need to be able to log out. In `header.js`, add a `logout` function to end the user's session with Magic, clear the user from the UserContext, and redirect back to the login page.\n\n```js\nconst logout = () =\u003e {\n  magic.user.logout().then(() =\u003e {\n    setUser({ user: null });\n    Router.push('/login');\n  });\n};\n```\n\n# Server\n\n## Validating the Auth Token (didToken)\n\nIn the `/api/login` route, simply verify the `DID token`, then send a `200` back to the client.\n\n```js\nexport default async function login(req, res) {\n  try {\n    const didToken = req.headers.authorization.substr(7);\n    await magic.token.validate(didToken);\n    res.status(200).json({ authenticated: true });\n  } catch (error) {\n    res.status(500).json({ error: error.message });\n  }\n}\n```\n\nThat's it! You now have a working Next.js app that includes Magic authentication for both magic links and social logins.\n\n## Deploying to Vercel\n\nFollow [this guide](https://magic.link/posts/magic-link-nextjs) for deploying to Vercel\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagiclabs%2Fexample-nextjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmagiclabs%2Fexample-nextjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagiclabs%2Fexample-nextjs/lists"}