Skip to content

Commit 73dec08

Browse files
committed
fix(sso): report a failed launch sign-in on the provider's sign-in link
1 parent 2cb6d3c commit 73dec08

2 files changed

Lines changed: 22 additions & 9 deletions

File tree

‎apps/sim/app/(auth)/sso/launch/[providerId]/route.test.ts‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,18 @@ describe('GET /sso/launch/[providerId]', () => {
101101
expect(mockSignInSSO).not.toHaveBeenCalled()
102102
})
103103

104-
it("falls back to the provider's sign-in link when sign-in cannot start", async () => {
105-
mockSignInSSO.mockResolvedValue(new Response('{}', { status: 400 }))
104+
it.each([
105+
['refuses', () => mockSignInSSO.mockResolvedValue(new Response('{}', { status: 400 }))],
106+
['throws', () => mockSignInSSO.mockRejectedValue(new Error('network'))],
107+
])("reports the failure on the provider's sign-in link when sign-in %s", async (_l, arrange) => {
108+
arrange()
106109

107110
const response = await open()
108111

109-
expect(response.headers.get('location')).toBe(SIGN_IN_LINK)
112+
const failure = new URL(response.headers.get('location') ?? '')
113+
expect(failure.pathname).toBe('/sso')
114+
expect(failure.searchParams.get('error')).toBe('sso_failed')
115+
expect(failure.searchParams.get('provider')).toBe('acme-okta')
110116
})
111117

112118
it('sends a rate-limited visitor to the sign-in link before any lookup', async () => {

‎apps/sim/app/(auth)/sso/launch/[providerId]/route.ts‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,25 @@ export const GET = withRouteHandler(async (request: NextRequest, context: RouteC
5757
`/sso?error=sso_failed&provider=${encodeURIComponent(providerId)}&callbackUrl=${encodeURIComponent(DEFAULT_POST_AUTH_ROUTE)}`,
5858
getBaseUrl()
5959
).toString()
60-
const signIn = await auth.api.signInSSO({
61-
body: { providerId, callbackURL: DEFAULT_POST_AUTH_ROUTE, errorCallbackURL },
62-
headers: request.headers,
63-
asResponse: true,
64-
})
60+
/** A sign-in that never starts is a failure, so it carries the error rather than a blank form. */
61+
let signIn: Response
62+
try {
63+
signIn = await auth.api.signInSSO({
64+
body: { providerId, callbackURL: DEFAULT_POST_AUTH_ROUTE, errorCallbackURL },
65+
headers: request.headers,
66+
asResponse: true,
67+
})
68+
} catch (error) {
69+
logger.error('SSO sign-in could not be started', { providerId, error })
70+
return NextResponse.redirect(errorCallbackURL)
71+
}
6572
const payload = (await signIn.json().catch(() => null)) as { url?: string } | null
6673
if (!signIn.ok || !payload?.url) {
6774
logger.error('SSO sign-in did not return an authorization URL', {
6875
providerId,
6976
status: signIn.status,
7077
})
71-
return NextResponse.redirect(signInLink)
78+
return NextResponse.redirect(errorCallbackURL)
7279
}
7380

7481
const response = NextResponse.redirect(payload.url)

0 commit comments

Comments
 (0)