![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@significa/auth-next
Advanced tools
Auth-related functions to handle access and refresh tokens in NextJS projects
This is work in progress and only suitable for internal use.
This package solves JWT-based authentication by saving the refresh token in an http-only cookie (accessible only server-side) and the access-token + a session indicator with the expiration date in client-acessible cookies.
Generate a new github PAT (Classic Personal Access Token).
Grant read:packages
Download packages from GitHub Package Registry.
Run npm login --scope=@significa --registry=https://npm.pkg.github.com
.
In the interactive CLI set your GitHub handle as the username and the newly generated PAT as the password (email can be anything).
npm install @significa/auth-next
More info: Working with the GitHub npm registry.
Create a lib/auth.ts
file to create your auth's config.
This package exposes a main Auth
class that should be initialized with your project's configuration:
// lib/auth.ts
import { Auth } from '@significa/auth-next'
import { API_URL } from 'common/constants'
export const auth = new Auth({
accessTokenKey: 'project_token',
sessionIndicatorKey: 'project_session',
refreshTokenKey: 'project_refresh_token',
/* configuration for the handler in Next's API Routes */
serverHandlers: {
login: {
fetch: (email, password) => {
return fetch(`${API_URL}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
password,
}),
})
},
parseResponse: async (res) => {
const { data } = await res.json()
return {
accessToken: data.access_token,
expires: data.expires,
refreshToken: data.refresh_token,
}
},
},
refresh: {
fetch: async (refreshToken: string) => {
return fetch(`${API_URL}/auth/refresh`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ refresh_token: refreshToken }),
})
},
parseResponse: async (res) => {
const { data } = await res.json()
return {
accessToken: data.access_token,
expires: data.expires,
refreshToken: data.refresh_token,
}
},
},
logout: {
fetch: async (refreshToken: string) => {
return fetch(`${API_URL}/auth/logout`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ refresh_token: refreshToken }),
})
},
},
},
})
If you're using Directus, you can use createDirectusHandlers
instead:
// lib/auth.ts
import { Auth, createDirectusHandlers } from '@significa/auth-next'
import { API_URL } from 'common/constants'
export const auth = new Auth({
accessTokenKey: 'project_token',
sessionIndicatorKey: 'project_session',
refreshTokenKey: 'project_refresh_token',
serverHandlers: createDirectusHandlers({
url: API_URL,
}),
})
Finally, you can create some aliases for page restrictions:
// still in lib/auth.ts
export const withRestriction = auth.restrictions.withRestriction
export const withSessionRefresh = auth.restrictions.withSessionRefresh
export const withGuestRestriction = withRestriction.bind(null, (isAuthed) =>
isAuthed ? '/app' : false
)
export const withAuthRestriction = withRestriction.bind(null, (isAuthed) =>
isAuthed ? false : '/login'
)
Create a pages/api/auth/[path].ts
file.
If you passed basePath
in your serverHandlers
config, make sure you create the file in the appropriate path
import { auth } from 'lib/auth'
export default auth.server.handler
auth.server.paths.login
.auth.server.paths.logout
.useLogin
and useLogout
hooksYou can create some hooks to centralize all the login/logout logic:
// useLogin.tsx
import { useRouter } from 'next/router'
import { useState } from 'react'
import { auth } from 'lib/auth'
export const useLogin = ({
onSuccess,
onError,
}: {
onSuccess?: () => void
onError?: () => void
} = {}) => {
const { push, query } = useRouter()
const [loading, setLoading] = useState(false)
const [error, setError] = useState(false)
const login = async ({
email,
password,
}: {
email: string
password: string
}) => {
setLoading(true)
try {
const res = await fetch(auth.server.paths.login, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
})
if (!res.ok) throw new Error()
if (typeof onSuccess === 'function') {
onSuccess()
} else {
// push to app by default
push(typeof query.returnTo === 'string' ? query.returnTo : '/app')
}
} catch (error) {
setError(true)
onError?.()
} finally {
setLoading(false)
}
}
const resetError = () => {
if (error) setError(false)
}
return { login, loading, error, resetError }
}
// useLogout.tsx
import { useRouter } from 'next/router'
import { useState } from 'react'
import { auth } from 'lib/auth'
export const useLogout = () => {
const { push } = useRouter()
const [loading, setLoading] = useState(false)
const logout = async () => {
setLoading(true)
try {
const res = await fetch(auth.server.paths.logout)
if (!res.ok) throw new Error()
} catch (error) {
// at least clear client-side cookies
auth.client.clearAccessToken()
auth.client.clearSessionIndicator()
} finally {
// redirect anyway
push('/')
setLoading(false)
}
}
return { logout, loading }
}
Finally, you can use the aliases in 'lib/auth' to lock routes:
// pages/app/index.tsx
import { withAuthRestriction } from 'lib/auth'
const AppHomepage = () => <div>Hello from App</div>
export const getServerSideProps = withAuthRestriction()
export default AppHomepage
withRestriction
already refreshes the session if necessary but, if you need, you can trigger a session refresh server-side by using withSessionRefresh
:
// pages/index.tsx
import { withSessionRefresh } from 'lib/auth'
...
export const getServerSideProps = withSessionRefresh()
useRefreshSession
This package also exports a useRefreshSession
hook that can be used to make client-side refreshes at a certain interval or whenever the window gains focus:
// _app.tsx
import { useRefreshSession, getDateDistance } from '@significa/auth-next'
import { auth } from 'lib/auth'
function MyApp({ Component, pageProps }: AppProps) {
useRefreshSession({
refreshPath: auth.server.paths.refresh,
shouldRefresh: () => {
const expiryDate = auth.client.getSessionIndicator()
if (!expiryDate) return false
return getDateDistance(new Date(expiryDate)) <= 30
},
onRefresh: () => {
queryClient.invalidateQueries(useMeQuery.getKey())
},
})
})
return ...
}
FAQs
Auth-related functions to handle access and refresh tokens in NextJS projects
We found that @significa/auth-next demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.