Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement refresh provider schema #581

Merged
merged 17 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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