Merged in feature/SW-3539-log-number-of-logins (pull request #3284)
feat(SW-3539): count number of logins * feat(SW-3539): count number of logins Approved-by: Anton Gunnarsson
This commit is contained in:
@@ -5,6 +5,7 @@ import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
|||||||
|
|
||||||
import { env } from "@/env/server"
|
import { env } from "@/env/server"
|
||||||
|
|
||||||
|
import { signInCounter } from "@/auth"
|
||||||
import { getToken } from "@/auth/scandic/getToken"
|
import { getToken } from "@/auth/scandic/getToken"
|
||||||
import { createSocialSession } from "@/auth/scandic/session"
|
import { createSocialSession } from "@/auth/scandic/session"
|
||||||
|
|
||||||
@@ -13,14 +14,17 @@ export async function GET(req: NextRequest) {
|
|||||||
const code = req.nextUrl.searchParams.get("code")
|
const code = req.nextUrl.searchParams.get("code")
|
||||||
const state = req.nextUrl.searchParams.get("state")
|
const state = req.nextUrl.searchParams.get("state")
|
||||||
const savedState = req.cookies.get("oauth_state")?.value
|
const savedState = req.cookies.get("oauth_state")?.value
|
||||||
|
const counter = signInCounter.init({ type: "curity" })
|
||||||
|
|
||||||
if (!code || !state) {
|
if (!code || !state) {
|
||||||
logger.error("Missing code or state", { url: req.nextUrl.toString() })
|
logger.error("Missing code or state", { url: req.nextUrl.toString() })
|
||||||
|
counter.fail("missing code or state")
|
||||||
throw new Error("Missing code or state, auth failed")
|
throw new Error("Missing code or state, auth failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!savedState) {
|
if (!savedState) {
|
||||||
logger.error("No saved state cookie", { url: req.nextUrl.toString() })
|
logger.error("No saved state cookie", { url: req.nextUrl.toString() })
|
||||||
|
counter.fail("missing state mismatch")
|
||||||
throw new Error("Missing saved oauth state, auth failed")
|
throw new Error("Missing saved oauth state, auth failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +34,7 @@ export async function GET(req: NextRequest) {
|
|||||||
saved: savedState,
|
saved: savedState,
|
||||||
url: req.nextUrl.toString(),
|
url: req.nextUrl.toString(),
|
||||||
})
|
})
|
||||||
|
counter.fail("state mismatch")
|
||||||
throw new Error("Invalid state, possible CSRF")
|
throw new Error("Invalid state, possible CSRF")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +48,8 @@ export async function GET(req: NextRequest) {
|
|||||||
expires_in: tokenResponse.expires_in,
|
expires_in: tokenResponse.expires_in,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
counter.success()
|
||||||
|
|
||||||
const c = await cookies()
|
const c = await cookies()
|
||||||
c.delete({ name: "oauth_state", path: "/" })
|
c.delete({ name: "oauth_state", path: "/" })
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Auth0Provider from "next-auth/providers/auth0"
|
|||||||
|
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
import { createLogger } from "@scandic-hotels/common/logger/createLogger"
|
||||||
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
||||||
import { getEuroBonusProfileData } from "@scandic-hotels/trpc/routers/partners/sas/getEuroBonusProfile"
|
import { getEuroBonusProfileData } from "@scandic-hotels/trpc/routers/partners/sas/getEuroBonusProfile"
|
||||||
|
|
||||||
@@ -13,6 +14,8 @@ import type { JWT } from "next-auth/jwt"
|
|||||||
const authLogger = createLogger("auth")
|
const authLogger = createLogger("auth")
|
||||||
export const PRE_REFRESH_TIME_IN_SECONDS = 180
|
export const PRE_REFRESH_TIME_IN_SECONDS = 180
|
||||||
|
|
||||||
|
export const signInCounter = createCounter("auth", "signIn")
|
||||||
|
|
||||||
async function refreshTokens(token: JWT) {
|
async function refreshTokens(token: JWT) {
|
||||||
try {
|
try {
|
||||||
if (!token.refresh_token) {
|
if (!token.refresh_token) {
|
||||||
@@ -118,6 +121,7 @@ const config: NextAuthConfig = {
|
|||||||
|
|
||||||
async jwt(params) {
|
async jwt(params) {
|
||||||
if (params.trigger === "signIn") {
|
if (params.trigger === "signIn") {
|
||||||
|
const counter = signInCounter.init({ type: "sas" })
|
||||||
const accessToken = params.account?.access_token
|
const accessToken = params.account?.access_token
|
||||||
// expires_at is in seconds for SAS, we need milliseconds
|
// expires_at is in seconds for SAS, we need milliseconds
|
||||||
const expiresAt = params.account?.expires_at
|
const expiresAt = params.account?.expires_at
|
||||||
@@ -125,16 +129,19 @@ const config: NextAuthConfig = {
|
|||||||
: null
|
: null
|
||||||
|
|
||||||
if (!accessToken) {
|
if (!accessToken) {
|
||||||
|
counter.fail("missing access token")
|
||||||
throw new Error("AuthError: Missing access token")
|
throw new Error("AuthError: Missing access token")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expiresAt) {
|
if (!expiresAt) {
|
||||||
|
counter.fail("missing expiry time")
|
||||||
throw new Error("AuthError: Missing expiry time")
|
throw new Error("AuthError: Missing expiry time")
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshToken = params.account?.refresh_token
|
const refreshToken = params.account?.refresh_token
|
||||||
|
|
||||||
if (!refreshToken) {
|
if (!refreshToken) {
|
||||||
|
counter.fail("missing refresh token")
|
||||||
authLogger.warn("⚠️ refreshToken missing")
|
authLogger.warn("⚠️ refreshToken missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +153,7 @@ const config: NextAuthConfig = {
|
|||||||
authLogger.error("Failed to fetch EuroBonus profile", error)
|
authLogger.error("Failed to fetch EuroBonus profile", error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
counter.success()
|
||||||
return {
|
return {
|
||||||
...params.token,
|
...params.token,
|
||||||
isLinked: eurobonusProfile?.linkStatus === "LINKED",
|
isLinked: eurobonusProfile?.linkStatus === "LINKED",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import NextAuth, { type NextAuthConfig, type User } from "next-auth"
|
|||||||
|
|
||||||
import { LoginTypeEnum } from "@scandic-hotels/common/constants/loginType"
|
import { LoginTypeEnum } from "@scandic-hotels/common/constants/loginType"
|
||||||
import { logger } from "@scandic-hotels/common/logger"
|
import { logger } from "@scandic-hotels/common/logger"
|
||||||
|
import { createCounter } from "@scandic-hotels/common/telemetry"
|
||||||
|
|
||||||
import { PRE_REFRESH_TIME_IN_SECONDS } from "@/constants/auth"
|
import { PRE_REFRESH_TIME_IN_SECONDS } from "@/constants/auth"
|
||||||
import { env } from "@/env/server"
|
import { env } from "@/env/server"
|
||||||
@@ -9,6 +10,8 @@ import { env } from "@/env/server"
|
|||||||
import type { JWT } from "next-auth/jwt"
|
import type { JWT } from "next-auth/jwt"
|
||||||
import type { OIDCConfig } from "next-auth/providers"
|
import type { OIDCConfig } from "next-auth/providers"
|
||||||
|
|
||||||
|
export const signInCounter = createCounter("auth", "signIn")
|
||||||
|
|
||||||
function getLoginType(user: User) {
|
function getLoginType(user: User) {
|
||||||
if (user?.login_with.includes("@")) {
|
if (user?.login_with.includes("@")) {
|
||||||
return LoginTypeEnum.email
|
return LoginTypeEnum.email
|
||||||
@@ -177,6 +180,9 @@ const baseConfig = {
|
|||||||
async jwt({ account, session, token, trigger, user, profile }) {
|
async jwt({ account, session, token, trigger, user, profile }) {
|
||||||
const loginType = getLoginType(user)
|
const loginType = getLoginType(user)
|
||||||
if (trigger === "signIn" && account) {
|
if (trigger === "signIn" && account) {
|
||||||
|
const counter = signInCounter.init({ type: "curity" })
|
||||||
|
counter.success()
|
||||||
|
|
||||||
const mfa_scope = profile?.amr == "urn:com:scandichotels:scandic-otp"
|
const mfa_scope = profile?.amr == "urn:com:scandichotels:scandic-otp"
|
||||||
const tokenExpiry = account.expires_at
|
const tokenExpiry = account.expires_at
|
||||||
? account.expires_at * 1000
|
? account.expires_at * 1000
|
||||||
|
|||||||
Reference in New Issue
Block a user