Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import SpotifyProvider from 'next-auth/providers/spotify'

import { db } from '@/lib/db'
import { authURL } from '@/lib/auth/configs'
import { refreshAccessToken } from '@/lib/auth/refresh-access-token'
import type { ExtendedUser } from '@/types'
// import { refreshAccessToken } from '@/lib/auth/refresh-access-token'

export const {
handlers: { GET, POST },
Expand Down Expand Up @@ -69,20 +68,32 @@ export const {
...token,
access_token: account.access_token,
token_type: account.token_type,
expires_at: account.expires_at
? account.expires_at * 1000
: Date.now(),
expires_at: Date.now() + 30000,
// expires_at: account.expires_at
// ? account.expires_at * 1000
// : Date.now(),
expires_in: account.expires_in,
refresh_token: account.refresh_token,
}
}

if (Date.now() < (token.expires_at as number)) {
return token
}
console.log('auth token ', {
refresh: token.refresh_token,
access: token.access_token,
})
console.log({
expires: new Date(token.expires_at as number).toLocaleTimeString(
'sv-SE',
),
})
return token

console.log('token expired')
return await refreshAccessToken(token)
// if (Date.now() < (token.expires_at as number)) {
// return token
// }

// console.log('token expired')
// return await refreshAccessToken(token)
},
async session({ session, token }: { session: any; token: any }) {
const user = {
Expand All @@ -92,7 +103,7 @@ export const {
expires_at: token.expires_at,
expires_in: token.expires_in,
refresh_token: token.refresh_token,
} satisfies ExtendedUser
}

session.user = user
session.error = token.error
Expand Down
4 changes: 1 addition & 3 deletions lib/auth/refresh-access-token.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { JWT } from 'next-auth/jwt'

const refreshAccessToken = async (token: JWT) => {
export const refreshAccessToken = async (token: JWT) => {
try {
const params = new URLSearchParams()
params.append('grant_type', 'refresh_token')
Expand Down Expand Up @@ -45,5 +45,3 @@ const refreshAccessToken = async (token: JWT) => {
}
}
}

export { refreshAccessToken }
7 changes: 2 additions & 5 deletions lib/current-profile.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { auth } from '@/auth'
import { ExtendedUser } from '@/types'
import { db } from '@/lib/db'

const currentProfile = async () => {
export const currentProfile = async () => {
const session = await auth()
const user = session?.user as ExtendedUser
const user = session?.user

if (!user || !user.email) return null

Expand All @@ -16,5 +15,3 @@ const currentProfile = async () => {

return profile
}

export { currentProfile }
100 changes: 87 additions & 13 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,111 @@
import { auth, signIn } from '@/auth'
import { NextResponse, type NextRequest } from 'next/server'
import {
ResponseCookies,
RequestCookies,
} from 'next/dist/server/web/spec-extension/cookies'
import { getToken, encode } from 'next-auth/jwt'

import { auth } from '@/auth'
import { refreshAccessToken } from '@/lib/auth/refresh-access-token'
import {
apiAuthPrefix,
authRoutes,
defaultLoginRedirect,
publicRoutes,
} from '@/lib/auth/routes'
import type { ExtendedSession } from '@/types'

export default auth(req => {
const { nextUrl } = req
const isLoggedIn = !!req.auth
const sessionCookieName =
process.env.NODE_ENV === 'development'
? 'authjs.session-token'
: '__Secure-authjs.session-token'

if ((req.auth as ExtendedSession)?.error === 'RefreshAccessTokenError') {
signIn('spotify')
}
export default auth(async request => {
const { nextUrl, auth } = request
const secret = process.env.NEXTAUTH_SECRET || ''

const token = await getToken({
req: request,
secret,
salt: sessionCookieName,
})

console.log('middleware token', {
refresh: token?.refresh_token,
access: token?.access_token,
})

const isApiAuthRoute = nextUrl.pathname.startsWith(apiAuthPrefix)
const isAuthRoute = authRoutes.includes(nextUrl.pathname)
const isPublicRoute = publicRoutes.includes(nextUrl.pathname)

if (isApiAuthRoute) return

if (isAuthRoute) {
if (isLoggedIn)
if (auth?.user) {
return Response.redirect(new URL(defaultLoginRedirect, nextUrl))
return
} else {
return
}
}

if (!isLoggedIn && !isPublicRoute) {
return Response.redirect(new URL('/auth/login', nextUrl))
if (!isPublicRoute) {
if (!auth?.user) {
return Response.redirect(new URL('/auth/login', nextUrl))
}
if (Date.now() < auth.user.expires_at) return

console.log('token expired')

const token = await getToken({
req: request,
secret,
salt: sessionCookieName,
})
if (!token) return Response.redirect(new URL('/auth/login', nextUrl))

const refreshedToken = await refreshAccessToken(token)
const encodedToken = await encode({
...refreshedToken,
secret,
salt: sessionCookieName,
})

console.log({
refreshedToken,
})

const response = NextResponse.next()
response.cookies.set(sessionCookieName, encodedToken)
applySetCookie(request, response)

return response
}
})

/**
* Copy cookies from the Set-Cookie header of the response to the Cookie header of the request,
* so that it will appear to SSR/RSC as if the user already has the new cookies.
* https://github.com/vercel/next.js/issues/49442#issuecomment-1679807704
*/
const applySetCookie = (req: NextRequest, res: NextResponse) => {
// parse the outgoing Set-Cookie header
const setCookies = new ResponseCookies(res.headers)
// Build a new Cookie header for the request by adding the setCookies
const newReqHeaders = new Headers(req.headers)
const newReqCookies = new RequestCookies(newReqHeaders)
setCookies.getAll().forEach(cookie => newReqCookies.set(cookie))
// set “request header overrides” on the outgoing response
NextResponse.next({
request: { headers: newReqHeaders },
}).headers.forEach((value, key) => {
if (
key === 'x-middleware-override-headers' ||
key.startsWith('x-middleware-request-')
) {
res.headers.set(key, value)
}
})
}

export const config = {
matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
}
28 changes: 14 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 4 additions & 17 deletions types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,16 @@ import type {
Playlist,
Artist,
} from '@spotify/web-api-ts-sdk'
import { Session, User } from 'next-auth'

export type ExtendedUser = User & {
access_token: string
token_type: string
expires_at: number
expires_in: number
refresh_token: string
}

export type ExtendedSession = Session & { error: string | undefined }
export type gamePlaylist = Artist | Playlist
export type gameTracks = (Track | PlaylistedTrack)[]

type gamePlaylist = Artist | Playlist
type gameTracks = (Track | PlaylistedTrack)[]

type gameData = {
export type gameData = {
playlist: gamePlaylist
tracks: gameTracks
}

type statistic = {
export type statistic = {
metric: string
value: string | number
}

export type { gamePlaylist, gameTracks, gameData, statistic }
14 changes: 14 additions & 0 deletions types/next-auth.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Session, User } from 'next-auth'

declare module 'next-auth' {
interface Session extends Session {
error: string | undefined
}
interface User extends User {
access_token: string
token_type: string
expires_at: number
expires_in: number
refresh_token: string
}
}