mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Display some error messages on the sign in page
Improves the UX by displaying some error messages on the sign in page
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth",
|
||||
"version": "3.0.0-beta.24",
|
||||
"version": "3.0.0-beta.25",
|
||||
"description": "Authentication for Next.js",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/iaincollins/next-auth.git",
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
:root {
|
||||
--color-background: #fff;
|
||||
--color-primary: #444;
|
||||
--color-control-border: #bbb;
|
||||
--color-button-hover-background: #f9f9f9;
|
||||
--color-button-active-background: #f5f5f5;
|
||||
--color-button-active-background: #f9f9f9;
|
||||
--color-button-active-border: #aaa;
|
||||
--border-width: 1px;
|
||||
--border-radius: .3rem;
|
||||
--color-error: #c94b4b;
|
||||
--color-info: #157efb;
|
||||
--color-seperator: #ccc;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--color-background);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
||||
@@ -39,7 +43,7 @@ input[type] {
|
||||
width: 100%;
|
||||
padding: .5rem 1rem;
|
||||
border: var(--border-width) solid var(--color-control-border);
|
||||
background: #fff;
|
||||
background: var(--color-background);
|
||||
font-size: 1rem;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: inset 0 .1rem .2rem rgba(0,0,0,.2);
|
||||
@@ -61,7 +65,7 @@ a.button {
|
||||
line-height: 1rem;
|
||||
&:link,
|
||||
&:visited {
|
||||
background-color: #fff;
|
||||
background-color: var(--color-background);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
@@ -72,21 +76,20 @@ a.button {
|
||||
padding: .75rem 1rem;
|
||||
border: var(--border-width) solid var(--color-control-border);
|
||||
color: var(--color-primary);
|
||||
background-color: #fff;
|
||||
background-color: var(--color-background);
|
||||
font-size: 1rem;
|
||||
border-radius: var(--border-radius);
|
||||
transition: all .1s ease-in-out;
|
||||
box-shadow: 0 0.15rem 0.3rem rgba(0,0,0,.15), inset 0 .1rem .2rem #fff, inset 0 -.1rem .1rem rgba(0,0,0,.05);
|
||||
box-shadow: 0 0.15rem 0.3rem rgba(0,0,0,.15), inset 0 .1rem .2rem var(--color-background), inset 0 -.1rem .1rem rgba(0,0,0,.05);
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-button-hover-background);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: 0 0.15rem 0.3rem rgba(0,0,0,.15), inset 0 .1rem .2rem #fff, inset 0 -.1rem .1rem rgba(0,0,0,.1);
|
||||
box-shadow: 0 0.15rem 0.3rem rgba(0,0,0,.15), inset 0 .1rem .2rem var(--color-background), inset 0 -.1rem .1rem rgba(0,0,0,.1);
|
||||
background-color: var(--color-button-active-background);
|
||||
border-color: var(--color-button-active-border);
|
||||
cursor: pointer;
|
||||
@@ -143,19 +146,34 @@ a.site {
|
||||
hr {
|
||||
display: block;
|
||||
border: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
border-top: 1px solid var(--color-seperator);
|
||||
margin: 1.5em auto 0 auto;
|
||||
overflow: visible;
|
||||
|
||||
&::before {
|
||||
content: "or";
|
||||
background: #fff;
|
||||
background: var(--color-background);
|
||||
color: #888;
|
||||
padding: 0 .4rem;
|
||||
position: relative;
|
||||
top: -.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
background: #f5f5f5;
|
||||
font-weight: 500;
|
||||
border-radius: 0.3rem;
|
||||
background: var(--color-info);
|
||||
color: #fff;
|
||||
p {
|
||||
text-align: left;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
> div,
|
||||
form {
|
||||
display: block;
|
||||
|
||||
@@ -235,12 +235,16 @@ export default async (req, res, userSuppliedOptions) => {
|
||||
res.json({ csrfToken })
|
||||
return done()
|
||||
case 'signin':
|
||||
if (options.pages.signIn) { return redirect(`${options.pages.signIn}${options.pages.signIn.includes('?') ? '&' : '?'}callbackUrl=${options.callbackUrl}`) }
|
||||
if (options.pages.signIn) {
|
||||
let redirectUrl = `${options.pages.signIn}${options.pages.signIn.includes('?') ? '&' : '?'}callbackUrl=${options.callbackUrl}`
|
||||
if (req.query.error) { redirectUrl = `${redirectUrl}&error=${req.query.error}` }
|
||||
return redirect(redirectUrl)
|
||||
}
|
||||
|
||||
pages.render(req, res, 'signin', { baseUrl, basePath, providers: Object.values(options.providers), callbackUrl: options.callbackUrl, csrfToken }, done)
|
||||
break
|
||||
case 'signout':
|
||||
if (options.pages.signOut) { return redirect(`${options.pages.signOut}${options.pages.signOut.includes('?') ? '&' : '?'}callbackUrl=${options.callbackUrl}`) }
|
||||
if (options.pages.signOut) { return redirect(`${options.pages.signOut}${options.pages.signOut.includes('?') ? '&' : '?'}error=${error}`) }
|
||||
|
||||
pages.render(req, res, 'signout', { baseUrl, basePath, csrfToken, callbackUrl: options.callbackUrl }, done)
|
||||
break
|
||||
|
||||
@@ -2,7 +2,7 @@ import { h } from 'preact' // eslint-disable-line no-unused-vars
|
||||
import render from 'preact-render-to-string'
|
||||
|
||||
export default ({ baseUrl, basePath, error, res }) => {
|
||||
const signinPageUrl = `${baseUrl}${basePath}/signin` // @TODO Make sign in URL configurable
|
||||
const signinPageUrl = `${baseUrl}${basePath}/signin`
|
||||
|
||||
let statusCode = 200
|
||||
let heading = <h1>Error</h1>
|
||||
@@ -15,51 +15,13 @@ export default ({ baseUrl, basePath, error, res }) => {
|
||||
case 'OAuthCreateAccount':
|
||||
case 'EmailCreateAccount':
|
||||
case 'Callback':
|
||||
heading = <h1>Sign in failed</h1>
|
||||
message =
|
||||
<div>
|
||||
<div className='message'>
|
||||
<p>Try signing with a different account.</p>
|
||||
</div>
|
||||
<p><a className='button' href={signinPageUrl}>Sign in</a></p>
|
||||
</div>
|
||||
break
|
||||
case 'OAuthAccountNotLinked':
|
||||
statusCode = 403
|
||||
heading = <h1>Sign in failed</h1>
|
||||
message =
|
||||
<div>
|
||||
<div className='message'>
|
||||
<p>An account associated with your email address already exists.</p>
|
||||
<p>Sign in with the same account you used originally to confirm your identity.</p>
|
||||
</div>
|
||||
<p><a className='button' href={signinPageUrl}>Sign in</a></p>
|
||||
</div>
|
||||
// @TODO Add this text when account linking is complete
|
||||
// <p>Once you are signed in, you can link your accounts.</p>
|
||||
// @TODO Display email sign in option if an email provider is configured
|
||||
break
|
||||
case 'EmailSignin':
|
||||
heading = <h1>Sign in failed</h1>
|
||||
message =
|
||||
<div>
|
||||
<div className='message'>
|
||||
<p>Unable to send email.</p>
|
||||
</div>
|
||||
<p><a className='button' href={signinPageUrl}>Sign in</a></p>
|
||||
</div>
|
||||
break
|
||||
case 'CredentialsSignin':
|
||||
statusCode = 403
|
||||
heading = <h1>Sign in failed</h1>
|
||||
message =
|
||||
<div>
|
||||
<div className='message'>
|
||||
<p>Check the details you provided are correct.</p>
|
||||
</div>
|
||||
<p><a className='button' href={signinPageUrl}>Sign in</a></p>
|
||||
</div>
|
||||
break
|
||||
// These messages are displayed in line on the sign in page
|
||||
res.status(302).setHeader('Location', `${signinPageUrl}?error=${error}`)
|
||||
res.end()
|
||||
return false
|
||||
case 'Configuration':
|
||||
statusCode = 500
|
||||
heading = <h1>Server error</h1>
|
||||
|
||||
@@ -18,6 +18,7 @@ function render (req, res, page, props, done) {
|
||||
break
|
||||
case 'error':
|
||||
html = error({ ...props, res })
|
||||
if (html === false) return done()
|
||||
break
|
||||
default:
|
||||
html = error(props)
|
||||
|
||||
@@ -2,7 +2,7 @@ import { h } from 'preact' // eslint-disable-line no-unused-vars
|
||||
import render from 'preact-render-to-string'
|
||||
|
||||
export default ({ req, csrfToken, providers, callbackUrl }) => {
|
||||
const { email } = req.query
|
||||
const { email, error } = req.query
|
||||
|
||||
// We only want to render providers
|
||||
const providersToRender = providers.filter(provider => {
|
||||
@@ -18,8 +18,37 @@ export default ({ req, csrfToken, providers, callbackUrl }) => {
|
||||
}
|
||||
})
|
||||
|
||||
let errorMessage
|
||||
if (error) {
|
||||
switch (error) {
|
||||
case 'Signin':
|
||||
case 'OAuthSignin':
|
||||
case 'OAuthCallback':
|
||||
case 'OAuthCreateAccount':
|
||||
case 'EmailCreateAccount':
|
||||
case 'Callback':
|
||||
errorMessage = <p>Try signing with a different account.</p>
|
||||
break
|
||||
case 'OAuthAccountNotLinked':
|
||||
errorMessage = <p>To confirm your identity, sign in with the same account you used originally.</p>
|
||||
break
|
||||
case 'EmailSignin':
|
||||
errorMessage = <p>Check your email address.</p>
|
||||
break
|
||||
case 'CredentialsSignin':
|
||||
errorMessage = <p>Sign in failed. Check the details you provided are correct.</p>
|
||||
break
|
||||
default:
|
||||
errorMessage = <p>Unable to sign in.</p>
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return render(
|
||||
<div className='signin'>
|
||||
{errorMessage && <div className='error'>
|
||||
{errorMessage}
|
||||
</div>}
|
||||
{providersToRender.map((provider, i) =>
|
||||
<div key={provider.id} className='provider'>
|
||||
{provider.type === 'oauth' &&
|
||||
|
||||
@@ -17,7 +17,7 @@ html[data-theme="dark"] .button:active {
|
||||
|
||||
.button--primary,
|
||||
.button--primary:hover{
|
||||
background: linear-gradient(0deg, var(--ifm-color-primary-darkest) 0%, var(--ifm-color-primary-lighter) 100%) !important;
|
||||
background: linear-gradient(0deg, #157efb 0%, var(--ifm-color-primary) 100%) !important;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ html[data-theme="dark"] .button:active {
|
||||
|
||||
html[data-theme="dark"] .button.button--secondary.button--outline {
|
||||
background: linear-gradient(0deg, #000000 0%, #222222 100%) !important;
|
||||
color: #eeee !important
|
||||
color: #eee !important
|
||||
}
|
||||
Reference in New Issue
Block a user