Skip to content

Commit

Permalink
feat: implement refresh provider schema (#581)
Browse files Browse the repository at this point in the history
Co-authored-by: Zoey <[email protected]>
  • Loading branch information
dommi10 and zoey-kaiser authored Nov 30, 2023
1 parent e005f0e commit 81627c4
Show file tree
Hide file tree
Showing 32 changed files with 1,342 additions and 175 deletions.
31 changes: 30 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,36 @@ jobs:
# start prod-app and curl from it
- run: "timeout 60 pnpm start & (sleep 45 && curl --fail localhost:3000)"

test-playground-refresh:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./playground-refresh
steps:
- uses: actions/checkout@v3

- name: Use Node.js 16.14.2
uses: actions/setup-node@v3
with:
node-version: 16.14.2

- uses: pnpm/action-setup@v2
name: Install pnpm
id: pnpm-install
with:
version: 8

# Install deps
- run: pnpm i

# Check building
- run: pnpm build

# start prod-app and curl from it
- run: "timeout 60 pnpm start & (sleep 45 && curl --fail localhost:$PORT)"
env:
AUTH_ORIGIN: "http://localhost:3002"
PORT: 3002

test-playground-authjs:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -97,5 +126,5 @@ jobs:
# start prod-app and curl from it
- run: "timeout 60 pnpm start & (sleep 45 && curl --fail localhost:$PORT)"
env:
AUTH_ORIGIN: 'http://localhost:3001'
AUTH_ORIGIN: "http://localhost:3001"
PORT: 3001
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
156 changes: 156 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,162 @@ 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 },
},
/**
* When refreshOnlyToken is set, only the token will be refreshed
*
*
*/
refreshOnlyToken?: true;
/**
* 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
Loading

0 comments on commit 81627c4

Please sign in to comment.