Skip to content

Commit

Permalink
feat: add documentation to refresh token schema
Browse files Browse the repository at this point in the history
  • Loading branch information
dommi10 committed Nov 22, 2023
1 parent 627489b commit 18155e6
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 3 deletions.
51 changes: 50 additions & 1 deletion docs/content/1.getting-started/3.quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,69 @@ and return a token that can be used to authenticate future requests in the respo
}
```

### Provider: `refresh`

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:
```ts
{
baseURL: '/api/auth',
endpoints: {
signIn: { path: '/login', method: 'post' },
signOut: { path: '/logout', method: 'post' },
signUp: { path: '/register', method: 'post' },
getSession: { path: '/session', method: 'get' }
refresh: { path: '/refresh', method: 'post' },
}
}
```

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).

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:
- [full nuxt app](https://github.com/sidebase/nuxt-auth/tree/main/playground-refresh)
- its [backend](https://github.com/sidebase/nuxt-auth/tree/main/playground-refresh/server/api/auth)
- its [`nuxt.config.ts`](https://github.com/sidebase/nuxt-auth/blob/main/playground-refresh/nuxt.config.ts)

::alert{type="info"}
The linked example-implementation only serves as a starting-point and is not considered to be secure.
::

The backend must accept a request with a body like:
```ts
{
username: '[email protected]',
password: 'hunter2'
}
```

and return a token that can be used to authenticate future requests in the response body, e.g., like:
```ts
{
tokens: {
accessToken: 'eyBlaBlub'
refreshToken: 'eyBlaubwww'
}
}
```

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).

## Finishing up

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

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

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

await signIn() // Sign in the user
await refresh() // Refresh the token
await signOut() // Sign out the user

```
```ts [authjs: Server side]
// file: e.g: ~/server/api/session.get.ts
Expand Down
150 changes: 150 additions & 0 deletions docs/content/2.configuration/2.nuxt-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,156 @@ type ProviderLocal = {
*/
sessionDataType?: SessionDataObject,
}

```
```ts [AuthProviders - refresh]
/**
* Configuration for the `refresh`-provider.
*/
type ProviderRefresh = {
/**
* Uses the `refresh` provider to facilitate autnetication. Currently, two providers exclusive are supported:
* - `authjs`: `next-auth` / `auth.js` based OAuth, Magic URL, Credential provider for non-static applications
* - `local`: Username and password provider with support for static-applications
* - `refresh`: Username and password provider with support for static-applications with refresh token logic
* Read more here: https://sidebase.io/nuxt-auth/v0.6/getting-started
*/
type: Extract<SupportedAuthProviders, 'refresh'>
/**
* Endpoints to use for the different methods. `nuxt-auth` will use this and the root-level `baseURL` to create the final request. E.g.:
* - `baseURL=/api/auth`, `path=/login` will result in a request to `/api/auth/login`
* - `baseURL=http://localhost:5000/_authenticate`, `path=/sign-in` will result in a request to `http://localhost:5000/_authenticate/sign-in`
*/
endpoints?: {
/**
* 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.
*
* @default { path: '/login', method: 'post' }
*/
signIn?: { path?: string, method?: RouterMethod },
/**
* What method and path to call to perform the sign-out. Set to false to disable.
*
* @default { path: '/logout', method: 'post' }
*/
signOut?: { path?: string, method?: RouterMethod } | false,
/**
* What method and path to call to perform the sign-up.
*
* @default { path: '/register', method: 'post' }
*/
signUp?: { path?: string, method?: RouterMethod },
/**
* 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.
*
* 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....`
*
* @default { path: '/session', method: 'get' }
* @example { path: '/user', method: 'get' }
*/
getSession?: { path?: string, method?: RouterMethod },
/**
* What method and path to call to perform the refresh.
*
* @default { path: '/refresh', method: 'post' }
*/
refresh?: { path?: string, method?: RouterMethod },
},
/**
* Pages that `nuxt-auth` needs to know the location off for redirects.
*/
pages?: {
/**
* 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.
*
* @default '/login'
*/
login?: string
},
/**
* Settings for the authentication-token that `nuxt-auth` receives from the `signIn` endpoint and that can be used to authenticate subsequent requests.
*/
token?: {
/**
* How to extract the authentication-token from the sign-in response.
*
* E.g., setting this to `/token/bearer` and returning an object like `{ token: { bearer: 'THE_AUTH_TOKEN' }, timestamp: '2023' }` from the `signIn` endpoint will
* result in `nuxt-auth` extracting and storing `THE_AUTH_TOKEN`.
*
* This follows the JSON Pointer standard, see it's RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901
*
* @default /token Access the `token` property of the sign-in response object
* @example / Access the root of the sign-in response object, useful when your endpoint returns a plain, non-object string as the token
*/
signInResponseTokenPointer?: string
/**
* 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`.
*
* @default Bearer
* @example Beer
*/
type?: string,
/**
* Header name to be used in requests that need to be authenticated, e.g., to be used in the `getSession` request.
*
* @default Authorization
* @example Auth
*/
headerName?: string,
/**
* 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.
*
* Note: Your backend may reject / expire the token earlier / differently.
*
* @default 1800
* @example 60 * 60 * 24
*/
maxAgeInSeconds?: number,
/**
* 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.
*
* See the specification here: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7
*
* @default 'lax'
* @example 'strict'
*/
sameSiteAttribute?: boolean | 'lax' | 'strict' | 'none' | undefined,
},
/**
* Settings for the authentication-refreshToken that `nuxt-auth` receives from the `signIn` endpoint and that can be used to authenticate subsequent requests.
*/
refreshToken?: {
/**
* How to extract the authentication-refreshToken from the sign-in response.
*
* E.g., setting this to `/token/refreshToken` and returning an object like `{ token: { refreshToken: 'THE_REFRESH__TOKEN' }, timestamp: '2023' }` from the `signIn` endpoint will
* result in `nuxt-auth` extracting and storing `THE_REFRESH__TOKEN`.
*
* This follows the JSON Pointer standard, see it's RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901
*
* @default /refreshToken Access the `refreshToken` property of the sign-in response object
* @example / Access the root of the sign-in response object, useful when your endpoint returns a plain, non-object string as the refreshToken
*/
signInResponseRefreshTokenPointer?: string
/**
* 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.
*
* Note: Your backend may reject / expire the refreshToken earlier / differently.
*
* @default 1800
* @example 60 * 60 * 24
*/
maxAgeInSeconds?: number,
},
/**
* Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint.
*
* @default { id: 'string | number' }
* @example { id: 'string', name: 'string', email: 'string' }
* @advanced_array_example { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account', subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" }
*/
sessionDataType?: SessionDataObject,
}
```
```ts [SessionConfig]
/**
Expand Down
103 changes: 103 additions & 0 deletions docs/content/3.application-side/2.session-access-and-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,56 @@ await signIn(credentials, { callbackUrl: 'https://sidebase.io', external: true }
// Trigger a sign-out
await signOut()

// Trigger a sign-out and send the user to the sign-out page afterwards
await signOut({ callbackUrl: '/signout' })
```
```ts [refresh]
const {
status,
data,
token,
lastRefreshedAt,
getSession,
signUp,
signIn,
signOut,
refresh,
refreshToken
} = useAuth()

// Session status, either `unauthenticated`, `loading`, `authenticated`
status.value

// Session data, either `undefined` (= authentication not attempted), `null` (= user unauthenticated), or session / user data your `getSession`-endpoint returns
data.value

// The fetched token that can be used to authenticate future requests. E.g., a JWT-Bearer token like so: `Bearer eyDFSJKLDAJ0-3249PPRFK3P5234SDFL;AFKJlkjdsjd.dsjlajhasdji89034`
token.value

// The fetched refreshToken that can be used to token . E.g., a refreshToken like so: `eyDFSJKLDAJ0-3249PPRFK3P5234SDFL;AFKJlkjdsjd.dsjlajhasdji89034`
refreshToken.value

// Time at which the session was last refreshed, either `undefined` if no refresh was attempted or a `Date`-object of the time the refresh happened
lastRefreshedAt.value

// Get / Reload the current session from the server, pass `{ required: true }` to force a login if no session exists
await getSession()

// Trigger a sign-in, where `credentials` are the credentials your sign-in endpoint expected, e.g. `{ username: 'bernd', password: 'hunter2' }`
await signIn(credentials)

// Trigger a sign-in with a redirect afterwards
await signIn(credentials, { callbackUrl: '/protected' })

// Trigger a sign-in with a redirect afterwards to an external page (if set, this will cause a hard refresh of the page)
await signIn(credentials, { callbackUrl: 'https://sidebase.io', external: true })

// Trigger a refresh, this will set token to new value
await refresh()

// Trigger a sign-out
await signOut()

// Trigger a sign-out and send the user to the sign-out page afterwards
await signOut({ callbackUrl: '/signout' })
```
Expand Down Expand Up @@ -168,6 +218,14 @@ await signIn(credentials, { callbackUrl: '/protected' })

await signOut(credentials, { callbackUrl: '/protected' })

await getSession(credentials, { callbackUrl: '/protected' })
```
```ts [refresh]
const credentials = { username: 'bernd', password: 'hunter2' }
await signIn(credentials, { callbackUrl: '/protected' })

await signOut(credentials, { callbackUrl: '/protected' })

await getSession(credentials, { callbackUrl: '/protected' })
```
::
Expand Down Expand Up @@ -233,6 +291,51 @@ setToken('new token')
// Helper method to quickly delete the token cookie (alias for rawToken.value = null)
clearToken()
```

```ts [refresh]
const {
status,
loading,
data,
lastRefreshedAt,
token,
rawToken,
setToken,
clearToken,
rawRefreshToken,
refreshToken
} = useAuthState()

// Session status, either `unauthenticated`, `loading`, `authenticated`
status.value

// Whether any http request is still pending
loading.value

// Session data, either `undefined` (= authentication not attempted), `null` (= user unauthenticated), or session / user data your `getSession`-endpoint returns
data.value

// Time at which the session was last refreshed, either `undefined` if no refresh was attempted or a `Date`-object of the time the refresh happened
lastRefreshedAt.value

// The fetched token that can be used to authenticate future requests. E.g., a JWT-Bearer token like so: `Bearer eyDFSJKLDAJ0-3249PPRFK3P5234SDFL;AFKJlkjdsjd.dsjlajhasdji89034`
token.value

// The fetched refreshToken that can be used to refresh the Token with refresh() methode.
refreshToken.value

// Cookie that containes the raw fetched token string. This token won't contain any modification or prefixes like `Bearer` or any other.
rawToken.value

// Cookie that containes the raw fetched refreshToken string.
rawRefreshToken.value

// Helper method to quickly set a new token (alias for rawToken.value = 'xxx')
setToken('new token')

// Helper method to quickly delete the token and refresh Token cookie (alias for rawToken.value = null and rawRefreshToken.value = null)
clearToken()
```
::

::alert{type="warning"}
Expand Down
4 changes: 2 additions & 2 deletions docs/content/3.application-side/3.custom-sign-in-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ const mySignInHandler = async ({ username, password }: { username: string, passw

Then call the `mySignInHandler({ username, password })` on login instead of the default `signIn(...)` method. You can find [all possible errors here](https://github.com/nextauthjs/next-auth/blob/aad0b8db0e8a163b3c3ae7dec3e9158e20d368f4/packages/next-auth/src/core/pages/signin.tsx#L4-L19). This file also contains the default error-messages that `nuxt-auth` would show to the user if you would not handle the error manually using `redirect: false`.

## Provider: `local`
## Provider: `local or refresh`

The only way to use the local provider does not come with a pre-made login page, so you will have to build one yourself. To do so:
The only way to use the local and refresh provider does not come with a pre-made login page, so you will have to build one yourself. To do so:
1. Create the page, e.g., `pages/login.vue`
2. Call the `signIn` method with the username and password your user has to enter on this page
3. Disable the page protection, if you have the global middleware enabled
Expand Down
1 change: 1 addition & 0 deletions docs/content/4.server-side/4.rest-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ All endpoints that NextAuth.js supports are also supported by `nuxt-auth`:
|--------------------------------|:-------------|
| `${basePath}/signin` | `GET` |
| `${basePath}/signin/:provider` | `POST` |
| `${basePath}/refresh/:provider` | `POST` |
| `${basePath}/callback/:provider` | `GET` `POST` |
| `${basePath}/signout` | `GET` `POST` |
| `${basePath}/session` | `GET` |
Expand Down

0 comments on commit 18155e6

Please sign in to comment.