Skip to content

Commit

Permalink
Display some error messages on the sign in page
Browse files Browse the repository at this point in the history
Improves the UX by displaying some error messages on the sign in page
  • Loading branch information
iaincollins committed Jul 27, 2020
1 parent 0724580 commit c3a91ae
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 59 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
38 changes: 28 additions & 10 deletions src/css/index.css
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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);
Expand All @@ -61,7 +65,7 @@ a.button {
line-height: 1rem;
&:link,
&:visited {
background-color: #fff;
background-color: var(--color-background);
color: var(--color-primary);
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
8 changes: 6 additions & 2 deletions src/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 5 additions & 43 deletions src/server/pages/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand Down
1 change: 1 addition & 0 deletions src/server/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
31 changes: 30 additions & 1 deletion src/server/pages/signin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand All @@ -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' &&
Expand Down
4 changes: 2 additions & 2 deletions www/src/css/buttons.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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
}

0 comments on commit c3a91ae

Please sign in to comment.