Skip to content

Commit 81627c4

Browse files
dommi10zoey-kaiser
andauthored
feat: implement refresh provider schema (#581)
Co-authored-by: Zoey <[email protected]>
1 parent e005f0e commit 81627c4

File tree

32 files changed

+1342
-175
lines changed

32 files changed

+1342
-175
lines changed

.github/workflows/ci.yaml

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,36 @@ jobs:
6767
# start prod-app and curl from it
6868
- run: "timeout 60 pnpm start & (sleep 45 && curl --fail localhost:3000)"
6969

70+
test-playground-refresh:
71+
runs-on: ubuntu-latest
72+
defaults:
73+
run:
74+
working-directory: ./playground-refresh
75+
steps:
76+
- uses: actions/checkout@v3
7077

78+
- name: Use Node.js 16.14.2
79+
uses: actions/setup-node@v3
80+
with:
81+
node-version: 16.14.2
82+
83+
- uses: pnpm/action-setup@v2
84+
name: Install pnpm
85+
id: pnpm-install
86+
with:
87+
version: 8
88+
89+
# Install deps
90+
- run: pnpm i
91+
92+
# Check building
93+
- run: pnpm build
94+
95+
# start prod-app and curl from it
96+
- run: "timeout 60 pnpm start & (sleep 45 && curl --fail localhost:$PORT)"
97+
env:
98+
AUTH_ORIGIN: "http://localhost:3002"
99+
PORT: 3002
71100

72101
test-playground-authjs:
73102
runs-on: ubuntu-latest
@@ -97,5 +126,5 @@ jobs:
97126
# start prod-app and curl from it
98127
- run: "timeout 60 pnpm start & (sleep 45 && curl --fail localhost:$PORT)"
99128
env:
100-
AUTH_ORIGIN: 'http://localhost:3001'
129+
AUTH_ORIGIN: "http://localhost:3001"
101130
PORT: 3001

docs/content/1.getting-started/3.quick-start.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,69 @@ and return a token that can be used to authenticate future requests in the respo
9191
}
9292
```
9393

94+
### Provider: `refresh`
95+
96+
The refresh provider does not require any additional steps, as it relies on an already existing backend. By default, the `refresh` provider will try to reach this backend using the following default-configuration:
97+
```ts
98+
{
99+
baseURL: '/api/auth',
100+
endpoints: {
101+
signIn: { path: '/login', method: 'post' },
102+
signOut: { path: '/logout', method: 'post' },
103+
signUp: { path: '/register', method: 'post' },
104+
getSession: { path: '/session', method: 'get' }
105+
refresh: { path: '/refresh', method: 'post' },
106+
}
107+
}
108+
```
109+
110+
So when you call the `signIn` method, the endpoint `/api/auth/login` will be hit with the `username` and `password` you pass as a body-payload. You likely have to modify these parameters to fit to your backend - you can adjust these parameters in your `nuxt.config.ts` using the options [specified here](/nuxt-auth/v0.6/configuration/nuxt-config).
111+
112+
Note: The backend can also be in the same Nuxt 3 application, e.g., have a look at this example in the `nuxt-auth` repository:
113+
- [full nuxt app](https://github.com/sidebase/nuxt-auth/tree/main/playground-refresh)
114+
- its [backend](https://github.com/sidebase/nuxt-auth/tree/main/playground-refresh/server/api/auth)
115+
- its [`nuxt.config.ts`](https://github.com/sidebase/nuxt-auth/blob/main/playground-refresh/nuxt.config.ts)
116+
117+
::alert{type="info"}
118+
The linked example-implementation only serves as a starting-point and is not considered to be secure.
119+
::
120+
121+
The backend must accept a request with a body like:
122+
```ts
123+
{
124+
username: '[email protected]',
125+
password: 'hunter2'
126+
}
127+
```
128+
129+
and return a token that can be used to authenticate future requests in the response body, e.g., like:
130+
```ts
131+
{
132+
tokens: {
133+
accessToken: 'eyBlaBlub'
134+
refreshToken: 'eyBlaubwww'
135+
}
136+
}
137+
```
138+
139+
So when you call the `refresh` method, the endpoint `/api/auth/refresh` will be hit with the `refreshToken` you pass as a body-payload. You likely have to modify these parameters to fit to your backend - you can adjust these parameters in your `nuxt.config.ts` using the options [specified here](/nuxt-auth/v0.6/configuration/nuxt-config).
140+
94141
## Finishing up
95142

96143
That's it! You can now use all user-related functionality, for example:
97144

98145
::code-group
99146
```ts [Application side]
100147
// file: e.g ~/pages/login.vue
101-
const { status, data, signIn, signOut } = useAuth()
148+
const { status, data, signIn, signOut, refresh } = useAuth()
102149

103150
status.value // Session status: `unauthenticated`, `loading`, `authenticated`
104151
data.value // Session data, e.g., expiration, user.email, ...
105152

106153
await signIn() // Sign in the user
154+
await refresh() // Refresh the token
107155
await signOut() // Sign out the user
156+
108157
```
109158
```ts [authjs: Server side]
110159
// file: e.g: ~/server/api/session.get.ts

docs/content/2.configuration/2.nuxt-config.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,162 @@ type ProviderLocal = {
228228
*/
229229
sessionDataType?: SessionDataObject,
230230
}
231+
232+
```
233+
```ts [AuthProviders - refresh]
234+
/**
235+
* Configuration for the `refresh`-provider.
236+
*/
237+
type ProviderRefresh = {
238+
/**
239+
* Uses the `refresh` provider to facilitate autnetication. Currently, two providers exclusive are supported:
240+
* - `authjs`: `next-auth` / `auth.js` based OAuth, Magic URL, Credential provider for non-static applications
241+
* - `local`: Username and password provider with support for static-applications
242+
* - `refresh`: Username and password provider with support for static-applications with refresh token logic
243+
* Read more here: https://sidebase.io/nuxt-auth/v0.6/getting-started
244+
*/
245+
type: Extract<SupportedAuthProviders, 'refresh'>
246+
/**
247+
* Endpoints to use for the different methods. `nuxt-auth` will use this and the root-level `baseURL` to create the final request. E.g.:
248+
* - `baseURL=/api/auth`, `path=/login` will result in a request to `/api/auth/login`
249+
* - `baseURL=http://localhost:5000/_authenticate`, `path=/sign-in` will result in a request to `http://localhost:5000/_authenticate/sign-in`
250+
*/
251+
endpoints?: {
252+
/**
253+
* What method and path to call to perform the sign-in. This endpoint must return a token that can be used to authenticate subsequent requests.
254+
*
255+
* @default { path: '/login', method: 'post' }
256+
*/
257+
signIn?: { path?: string, method?: RouterMethod },
258+
/**
259+
* What method and path to call to perform the sign-out. Set to false to disable.
260+
*
261+
* @default { path: '/logout', method: 'post' }
262+
*/
263+
signOut?: { path?: string, method?: RouterMethod } | false,
264+
/**
265+
* What method and path to call to perform the sign-up.
266+
*
267+
* @default { path: '/register', method: 'post' }
268+
*/
269+
signUp?: { path?: string, method?: RouterMethod },
270+
/**
271+
* What method and path to call to fetch user / session data from. `nuxt-auth` will send the token received upon sign-in as a header along this request to authenticate.
272+
*
273+
* Refer to the `token` configuration to configure how `nuxt-auth` uses the token in this request. By default it will be send as a bearer-authentication header like so: `Authentication: Bearer eyNDSNJDASNMDSA....`
274+
*
275+
* @default { path: '/session', method: 'get' }
276+
* @example { path: '/user', method: 'get' }
277+
*/
278+
getSession?: { path?: string, method?: RouterMethod },
279+
/**
280+
* What method and path to call to perform the refresh.
281+
*
282+
* @default { path: '/refresh', method: 'post' }
283+
*/
284+
refresh?: { path?: string, method?: RouterMethod },
285+
},
286+
/**
287+
* When refreshOnlyToken is set, only the token will be refreshed
288+
*
289+
*
290+
*/
291+
refreshOnlyToken?: true;
292+
/**
293+
* Pages that `nuxt-auth` needs to know the location off for redirects.
294+
*/
295+
pages?: {
296+
/**
297+
* Path of the login-page that the user should be redirected to, when they try to access a protected page without being logged in. This page will also not be blocked by the global middleware.
298+
*
299+
* @default '/login'
300+
*/
301+
login?: string
302+
},
303+
/**
304+
* Settings for the authentication-token that `nuxt-auth` receives from the `signIn` endpoint and that can be used to authenticate subsequent requests.
305+
*/
306+
token?: {
307+
/**
308+
* How to extract the authentication-token from the sign-in response.
309+
*
310+
* E.g., setting this to `/token/bearer` and returning an object like `{ token: { bearer: 'THE_AUTH_TOKEN' }, timestamp: '2023' }` from the `signIn` endpoint will
311+
* result in `nuxt-auth` extracting and storing `THE_AUTH_TOKEN`.
312+
*
313+
* This follows the JSON Pointer standard, see it's RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901
314+
*
315+
* @default /token Access the `token` property of the sign-in response object
316+
* @example / Access the root of the sign-in response object, useful when your endpoint returns a plain, non-object string as the token
317+
*/
318+
signInResponseTokenPointer?: string
319+
/**
320+
* Header type to be used in requests. This in combination with `headerName` is used to construct the final authentication-header `nuxt-auth` uses, e.g, for requests via `getSession`.
321+
*
322+
* @default Bearer
323+
* @example Beer
324+
*/
325+
type?: string,
326+
/**
327+
* Header name to be used in requests that need to be authenticated, e.g., to be used in the `getSession` request.
328+
*
329+
* @default Authorization
330+
* @example Auth
331+
*/
332+
headerName?: string,
333+
/**
334+
* Maximum age to store the authentication token for. After the expiry time the token is automatically deleted on the application side, i.e., in the users' browser.
335+
*
336+
* Note: Your backend may reject / expire the token earlier / differently.
337+
*
338+
* @default 1800
339+
* @example 60 * 60 * 24
340+
*/
341+
maxAgeInSeconds?: number,
342+
/**
343+
* The cookie sameSite policy. Can be used as a form of csrf forgery protection. If set to `strict`, the cookie will only be passed with requests to the same 'site'. Typically, this includes subdomains. So, a sameSite: strict cookie set by app.mysite.com will be passed to api.mysite.com, but not api.othersite.com.
344+
*
345+
* See the specification here: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7
346+
*
347+
* @default 'lax'
348+
* @example 'strict'
349+
*/
350+
sameSiteAttribute?: boolean | 'lax' | 'strict' | 'none' | undefined,
351+
},
352+
/**
353+
* Settings for the authentication-refreshToken that `nuxt-auth` receives from the `signIn` endpoint and that can be used to authenticate subsequent requests.
354+
*/
355+
refreshToken?: {
356+
/**
357+
* How to extract the authentication-refreshToken from the sign-in response.
358+
*
359+
* E.g., setting this to `/token/refreshToken` and returning an object like `{ token: { refreshToken: 'THE_REFRESH__TOKEN' }, timestamp: '2023' }` from the `signIn` endpoint will
360+
* result in `nuxt-auth` extracting and storing `THE_REFRESH__TOKEN`.
361+
*
362+
* This follows the JSON Pointer standard, see it's RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901
363+
*
364+
* @default /refreshToken Access the `refreshToken` property of the sign-in response object
365+
* @example / Access the root of the sign-in response object, useful when your endpoint returns a plain, non-object string as the refreshToken
366+
*/
367+
signInResponseRefreshTokenPointer?: string
368+
/**
369+
* Maximum age to store the authentication token for. After the expiry time the token is automatically deleted on the application side, i.e., in the users' browser.
370+
*
371+
* Note: Your backend may reject / expire the refreshToken earlier / differently.
372+
*
373+
* @default 1800
374+
* @example 60 * 60 * 24
375+
*/
376+
maxAgeInSeconds?: number,
377+
},
378+
/**
379+
* Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint.
380+
*
381+
* @default { id: 'string | number' }
382+
* @example { id: 'string', name: 'string', email: 'string' }
383+
* @advanced_array_example { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account', subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" }
384+
*/
385+
sessionDataType?: SessionDataObject,
386+
}
231387
```
232388
```ts [SessionConfig]
233389
/**

0 commit comments

Comments
 (0)