diff --git a/package.json b/package.json
index fa1a593..2d2abd9 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"./types": "./build/src/auth/types.js",
"./auth_provider": "./build/providers/auth_provider.js",
"./plugins/api_client": "./build/src/auth/plugins/japa/api_client.js",
+ "./plugins/browser_client": "./build/src/auth/plugins/japa/browser_client.js",
"./services/main": "./build/services/auth.js",
"./core/token": "./build/src/core/token.js",
"./core/guard_user": "./build/src/core/guard_user.js",
@@ -78,8 +79,10 @@
"@commitlint/config-conventional": "^18.0.0",
"@japa/api-client": "^2.0.0",
"@japa/assert": "^2.0.0",
+ "@japa/browser-client": "^2.0.0",
"@japa/expect-type": "^2.0.0",
"@japa/file-system": "^2.0.0",
+ "@japa/plugin-adonisjs": "^2.0.0",
"@japa/runner": "^3.0.4",
"@japa/snapshot": "^2.0.0",
"@swc/core": "1.3.82",
@@ -96,6 +99,7 @@
"husky": "^8.0.3",
"luxon": "^3.4.3",
"np": "^8.0.4",
+ "playwright": "^1.39.0",
"prettier": "^3.0.3",
"set-cookie-parser": "^2.6.0",
"sqlite3": "^5.1.6",
@@ -140,7 +144,9 @@
"@adonisjs/core": "^6.1.5-31",
"@adonisjs/lucid": "^19.0.0-3",
"@adonisjs/session": "^7.0.0-13",
- "@japa/api-client": "^2.0.0"
+ "@japa/api-client": "^2.0.0",
+ "@japa/browser-client": "^2.0.0",
+ "@japa/plugin-adonisjs": "^2.0.0"
},
"peerDependenciesMeta": {
"@adonisjs/lucid": {
@@ -151,6 +157,12 @@
},
"@japa/api-client": {
"optional": true
+ },
+ "@japa/browser-client": {
+ "optional": true
+ },
+ "@japa/plugin-adonisjs": {
+ "optional": true
}
}
}
diff --git a/src/auth/plugins/japa/api_client.ts b/src/auth/plugins/japa/api_client.ts
index 01791ff..d99dd2f 100644
--- a/src/auth/plugins/japa/api_client.ts
+++ b/src/auth/plugins/japa/api_client.ts
@@ -9,8 +9,11 @@
///
+import type { PluginFn } from '@japa/runner/types'
import { ApiClient, ApiRequest } from '@japa/api-client'
import type { ApplicationService } from '@adonisjs/core/types'
+
+import debug from '../../debug.js'
import type { Authenticators, GuardContract, GuardFactory } from '../../types.js'
declare module '@japa/api-client' {
@@ -58,51 +61,62 @@ declare module '@japa/api-client' {
* HTTP requests using the Japa API client
*/
export const authApiClient = (app: ApplicationService) => {
- ApiRequest.macro('loginAs', function (this: ApiRequest, user) {
- this.authData = {
- guard: '__default__',
- user: user,
- }
- return this
- })
+ const pluginFn: PluginFn = function () {
+ debug('installing auth api client plugin')
- ApiRequest.macro('withGuard', function <
- K extends keyof Authenticators,
- Self extends ApiRequest,
- >(this: Self, guard: K) {
- return {
- loginAs: (user) => {
- this.authData = {
- guard,
- user: user,
- }
- return this
- },
- }
- })
+ ApiRequest.macro('loginAs', function (this: ApiRequest, user) {
+ this.authData = {
+ guard: '__default__',
+ user: user,
+ }
+ return this
+ })
- /**
- * Hook into the request and login the user
- */
- ApiClient.setup(async (request) => {
- const auth = await app.container.make('auth.manager')
- const authData = request['authData']
- if (!authData) {
- return
- }
+ ApiRequest.macro('withGuard', function <
+ K extends keyof Authenticators,
+ Self extends ApiRequest,
+ >(this: Self, guard: K) {
+ return {
+ loginAs: (user) => {
+ this.authData = {
+ guard,
+ user: user,
+ }
+ return this
+ },
+ }
+ })
+
+ /**
+ * Hook into the request and login the user
+ */
+ ApiClient.setup(async (request) => {
+ const auth = await app.container.make('auth.manager')
+ const authData = request['authData']
+ if (!authData) {
+ return
+ }
- const client = auth.createAuthenticatorClient()
- const guard = authData.guard === '__default__' ? client.use() : client.use(authData.guard)
- const requestData = await (guard as GuardContract).authenticateAsClient(authData.user)
+ const client = auth.createAuthenticatorClient()
+ const guard = authData.guard === '__default__' ? client.use() : client.use(authData.guard)
+ const requestData = await (guard as GuardContract).authenticateAsClient(
+ authData.user
+ )
- if (requestData.headers) {
- request.headers(requestData.headers)
- }
- if (requestData.session) {
- request.withSession(requestData.session)
- }
- if (requestData.cookies) {
- request.cookies(requestData.cookies)
- }
- })
+ if (requestData.headers) {
+ debug('defining headers with api client request %O', requestData.headers)
+ request.headers(requestData.headers)
+ }
+ if (requestData.session) {
+ debug('defining session with api client request %O', requestData.session)
+ request.withSession(requestData.session)
+ }
+ if (requestData.cookies) {
+ debug('defining session with api client request %O', requestData.session)
+ request.cookies(requestData.cookies)
+ }
+ })
+ }
+
+ return pluginFn
}
diff --git a/src/auth/plugins/japa/browser_client.ts b/src/auth/plugins/japa/browser_client.ts
new file mode 100644
index 0000000..40591d7
--- /dev/null
+++ b/src/auth/plugins/japa/browser_client.ts
@@ -0,0 +1,90 @@
+/*
+ * @adoniss/auth
+ *
+ * (c) AdonisJS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+///
+///
+
+import { RuntimeException } from '@poppinss/utils'
+import type { PluginFn } from '@japa/runner/types'
+import { decoratorsCollection } from '@japa/browser-client'
+import type { ApplicationService } from '@adonisjs/core/types'
+
+import debug from '../../debug.js'
+import type { Authenticators, GuardContract, GuardFactory } from '../../types.js'
+
+declare module 'playwright' {
+ export interface BrowserContext {
+ /**
+ * Login a user using the default authentication
+ * guard when using the browser context to
+ * make page visits
+ */
+ loginAs(user: {
+ [K in keyof Authenticators]: Authenticators[K] extends GuardFactory
+ ? ReturnType extends GuardContract
+ ? A
+ : never
+ : never
+ }): Promise
+
+ /**
+ * Define the authentication guard for login
+ */
+ withGuard(
+ guard: K
+ ): {
+ /**
+ * Login a user using a specific auth guard
+ */
+ loginAs(
+ user: Authenticators[K] extends GuardFactory
+ ? ReturnType extends GuardContract
+ ? A
+ : never
+ : never
+ ): Promise
+ }
+ }
+}
+
+export const authBrowserClient = (app: ApplicationService) => {
+ const pluginFn: PluginFn = async function () {
+ debug('installing auth browser client plugin')
+
+ const auth = await app.container.make('auth.manager')
+
+ decoratorsCollection.register({
+ context(context) {
+ context.loginAs = async function (user) {
+ const client = auth.createAuthenticatorClient()
+ const guard = client.use() as GuardContract
+ const requestData = await guard.authenticateAsClient(user)
+
+ if (requestData.headers) {
+ throw new RuntimeException(`Cannot use "${guard.driverName}" guard with browser client`)
+ }
+
+ if (requestData.cookies) {
+ debug('defining cookies with browser context %O', requestData.cookies)
+ Object.keys(requestData.cookies).forEach((cookie) => {
+ context.setCookie(cookie, requestData.cookies![cookie])
+ })
+ }
+
+ if (requestData.session) {
+ debug('defining session with browser context %O', requestData.session)
+ context.setSession(requestData.session)
+ }
+ }
+ },
+ })
+ }
+
+ return pluginFn
+}