Skip to content
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
2 changes: 1 addition & 1 deletion components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function Header () {
className={styles.button}
onClick={(e) => {
e.preventDefault()
signOut()
signOut({ redirect: false })
}}
>
Sign out
Expand Down
8 changes: 0 additions & 8 deletions pages/credentials.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ export default function Page () {
}
const response = await signIn('credentials', options)
setResponse(response)
if (response.ok) {
window.alert('Manually refreshing to update session, if login was successful')
window.location.reload()
}
}

const handleLogout = (options) => async () => {
Expand All @@ -22,10 +18,6 @@ export default function Page () {
}
const response = await signOut(options)
setResponse(response)
if (response.ok) {
window.alert('Manually refreshing to update session, if logout was successful')
window.location.reload()
}
}

const [session] = useSession()
Expand Down
30 changes: 17 additions & 13 deletions src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,10 @@ const setOptions = ({
}

// Universal method (client + server)
export const getSession = async ({ req, ctx, triggerEvent = true } = {}) => {
// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getSession() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
if (!req && ctx && ctx.req) { req = ctx.req }

// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getSession() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
export async function getSession ({ ctx, req = ctx?.req, triggerEvent = true } = {}) {
const baseUrl = _apiBaseUrl()
const fetchOptions = req ? { headers: { cookie: req.headers.cookie } } : {}
const session = await _fetchData(`${baseUrl}/session`, fetchOptions)
Expand All @@ -130,12 +128,10 @@ export const getSession = async ({ req, ctx, triggerEvent = true } = {}) => {
}

// Universal method (client + server)
const getCsrfToken = async ({ req, ctx } = {}) => {
// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getCsrfToken() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
if (!req && ctx && ctx.req) { req = ctx.req }

// If passed 'appContext' via getInitialProps() in _app.js then get the req
// object from ctx and use that for the req value to allow getCsrfToken() to
// work seemlessly in getInitialProps() on server side pages *and* in _app.js.
async function getCsrfToken ({ ctx, req = ctx?.req } = {}) {
const baseUrl = _apiBaseUrl()
const fetchOptions = req ? { headers: { cookie: req.headers.cookie } } : {}
const data = await _fetchData(`${baseUrl}/csrf`, fetchOptions)
Expand Down Expand Up @@ -287,10 +283,16 @@ export async function signIn (provider, options = {}, authorizationParams = {})
}

const error = new URL(data.url).searchParams.get('error')

if (res.ok) {
await __NEXTAUTH._getSession({ event: 'storage' })
}

return {
error,
status: res.status,
ok: res.ok
ok: res.ok,
url: error ? null : data.url
}
}

Expand Down Expand Up @@ -326,6 +328,8 @@ export async function signOut (options = {}) {
return
}

await __NEXTAUTH._getSession({ event: 'storage' })

return data
}

Expand Down
39 changes: 39 additions & 0 deletions www/docs/getting-started/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,35 @@ e.g.

The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect). By default it requires the URL to be an absolute URL at the same hostname, or else it will redirect to the homepage. You can define your own redirect callback to allow other URLs, including supporting relative URLs.

#### Using the redirect: false option

When you use the `credentials` provider, you might not want the user to redirect to an error page if an error occurs, so you can handle any errors (like wrong credentials given by the user) on the same page. For that, you can pass `redirect: false` in the second parameter object. `signIn` then will return a Promise, that resolves to the following:

```ts
{
/**
* Will be different error codes,
* depending on the type of error.
*/
error: string | undefined
/**
* HTTP status code,
* hints the kind of error that happened.
*/
status: number
/**
* `true` if the signin was successful
*/
ok: boolean
/**
* `null` if there was an error,
* otherwise the url the user
* should have been redirected to.
*/
url: string | null
}
```

#### Additional params

It is also possible to pass additional parameters to the `/authorize` endpoint through the third argument of `signIn()`.
Expand Down Expand Up @@ -256,6 +285,16 @@ e.g. `signOut({ callbackUrl: 'http://localhost:3000/foo' })`

The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect). By default this means it must be an absolute URL at the same hostname (or else it will default to the homepage); you can define your own custom redirect callback to allow other URLs, including supporting relative URLs.

#### Using the redirect: false option

If you pass `redirect: false` to `signOut`, the page will not reload. The session will be deleted, and the `useSession` hook is notified, so any indication about the user will be shown as logged out automatically. It can give a very nice experience for the user.

:::tip
If you need to redirect to another page but you want to avoid a page reload, you can try:
`const data = await signOut({redirect: false, callbackUrl: "/foo"})`
where `data.url` is the validated url you can redirect the user to without any flicker by using Next.js's `useRouter().push(data.url)`
:::

---

## Provider
Expand Down