@@ -6,7 +6,11 @@ import Credentials from "../../src/providers/credentials.js"
66import { logger , makeAuthRequest , testConfig } from "../utils.js"
77import { skipCSRFCheck } from "../../src/index.js"
88import { CredentialsSignin , InvalidCheck } from "../../src/errors.js"
9- import { state } from "../../src/lib/actions/callback/oauth/checks.js"
9+ import {
10+ nonce ,
11+ pkce ,
12+ state ,
13+ } from "../../src/lib/actions/callback/oauth/checks.js"
1014
1115describe ( "assert GET callback action" , ( ) => {
1216 beforeEach ( ( ) => {
@@ -149,6 +153,70 @@ describe("assert GET callback action", () => {
149153 } )
150154} )
151155
156+ describe ( "OAuth check cookies are bound to their provider" , ( ) => {
157+ const cookieOptions = { secure : true , sameSite : "lax" as const , httpOnly : true }
158+ const cookies = {
159+ state : { name : "authjs.state" , options : cookieOptions } ,
160+ nonce : { name : "authjs.nonce" , options : cookieOptions } ,
161+ pkceCodeVerifier : {
162+ name : "authjs.pkce.code_verifier" ,
163+ options : cookieOptions ,
164+ } ,
165+ }
166+
167+ function optionsFor ( id : string , checks : Array < "state" | "nonce" | "pkce" > ) {
168+ return {
169+ logger,
170+ provider : { id, checks } ,
171+ jwt : { secret : "secret" } ,
172+ cookies,
173+ } as any
174+ }
175+
176+ it ( "accepts a state cookie on the same provider's callback" , async ( ) => {
177+ const created = ( await state . create ( optionsFor ( "github" , [ "state" ] ) ) ) as any
178+ const value = await state . use (
179+ { [ cookies . state . name ] : created . cookie . value } ,
180+ [ ] ,
181+ optionsFor ( "github" , [ "state" ] )
182+ )
183+ expect ( value ) . toBe ( created . value )
184+ } )
185+
186+ it ( "rejects a state cookie minted for a different provider" , async ( ) => {
187+ const created = ( await state . create ( optionsFor ( "github" , [ "state" ] ) ) ) as any
188+ await expect (
189+ state . use (
190+ { [ cookies . state . name ] : created . cookie . value } ,
191+ [ ] ,
192+ optionsFor ( "google" , [ "state" ] )
193+ )
194+ ) . rejects . toThrow ( InvalidCheck )
195+ } )
196+
197+ it ( "rejects a nonce cookie minted for a different provider" , async ( ) => {
198+ const created = ( await nonce . create ( optionsFor ( "github" , [ "nonce" ] ) ) ) as any
199+ await expect (
200+ nonce . use (
201+ { [ cookies . nonce . name ] : created . cookie . value } ,
202+ [ ] ,
203+ optionsFor ( "google" , [ "nonce" ] )
204+ )
205+ ) . rejects . toThrow ( InvalidCheck )
206+ } )
207+
208+ it ( "rejects a PKCE verifier cookie minted for a different provider" , async ( ) => {
209+ const created = ( await pkce . create ( optionsFor ( "github" , [ "pkce" ] ) ) ) as any
210+ await expect (
211+ pkce . use (
212+ { [ cookies . pkceCodeVerifier . name ] : created . cookie . value } ,
213+ [ ] ,
214+ optionsFor ( "google" , [ "pkce" ] )
215+ )
216+ ) . rejects . toThrow ( InvalidCheck )
217+ } )
218+ } )
219+
152220describe ( "assert POST callback action" , ( ) => {
153221 describe ( "Credentials provider" , ( ) => {
154222 it ( "should return error=CredentialSignin and code=credentials if authorize returns null" , async ( ) => {
0 commit comments