Draw your own sign-in page
Goal
Make the way into your portal look like the rest of your site: a Sign in page, a Create account page and a Forgotten your password? page that you drew, with your landing and pricing pages open to anybody who has not signed in yet.
Before you start
- A portal set to People who sign in. See Ask visitors to sign in.
- Somebody who runs your Parsware installation has set up email sending. Creating an account and resetting a password both send an email.
1. Draw the screens
In your portal's Studio app, draw three screens. Name them whatever you like — these names are only examples:
| Screen | What is on it |
|---|---|
| Sign in | An email box, a password box, a code box (see below), a Sign in button |
| Create account | A name box, an email box, a password box, a Create account button |
| Forgot password | An email box and a Send the link button |
For each box, select it and set Takes: An email address for the address and A password for the password. A password box hides what is typed and has an eye to show it.
Bind each box to a state field — state.email, state.password — as you would any form.
2. Give each button its handler
| Button | Handler |
|---|---|
| Sign in | signIn(getState("email"), getState("password"), getState("code"), "needsCode"); |
| Create account | signUp(getState("name"), getState("email"), getState("password"), "sent"); |
| Send the link | requestPasswordReset(getState("email"), "sent"); |
The password goes to the platform, exactly as it does from the platform's own sign-in page. It is never sent to anything of yours, and nothing on your page can read the session that comes back.
The last argument is the name of a state field, and it is how your page finds out what happened:
signUpandrequestPasswordResetset it to true once the email has gone. Put the form in one stack with Visible!state.sent, and a "Check your email" message in another with Visiblestate.sent.signInsets it to true when the account has two-step sign-in turned on. Give the code box Visiblestate.needsCode: the visitor types the six digits and presses Sign in again.
The next line of a handler runs whether or not the call worked, so navigate(...) after signUp
would go there even when the address was refused. Showing the message from the state field means it
only appears when the email has really gone.
If the platform refuses — a wrong password, an address that already has an account — the visitor is told why in a message, in their language. You do not have to draw anything for that.
3. Tell the portal about them
- Open your solution, choose Portals, and open the portal.
- In Sign-in screen, choose Sign in.
- In Open before signing in, choose the screens anybody may see: your landing page, your pricing page, Create account and Forgot password.
- Press Save.
What a visitor sees
Somebody who has not signed in can read every open screen. If they go to any other screen — by a link, a bookmark or a button — they see your Sign in screen, at that screen's address. Once they sign in, the same address becomes the screen they asked for.
So a Your account link in your top bar works for everybody: it shows the sign-in to a stranger and the account to somebody signed in.
Somebody who signs in on the Sign in screen itself goes on to your portal's start screen.
A screen that is not open is not hidden in the page — it is never sent to somebody who has not signed in. What they receive in its place is your sign-in screen.
4. Draw the page a reset link opens, too (optional)
When somebody asks for a password-reset link, the email's link opens a page where they choose a new password. You can draw that page as well.
-
Draw a screen — New password, say — with two password boxes bound to
state.passwordandstate.again, and a Set the password button with this handler:if (getState("password") != getState("again")) {notifyError("The two passwords are different.");} else {resetPassword(getState("password"));} -
In the portal, choose it in New-password screen. That box appears once a Sign-in screen is chosen, because the sign-in screen is where the visitor goes next.
Your screen only ever sees the password. The link carries a secret from the email. The platform
takes it out of the address before your screen appears and adds it back itself when your button calls
resetPassword. Nothing on your page can read it.
When the password is set, the visitor is signed out everywhere, taken to your Sign in screen, and told their password is set. If somebody opens New password without following a link, pressing the button tells them to open the link in their email.
You don't need to add New password to Open before signing in. Whoever holds a reset link is signed out by definition, so the page is always shown to them.
5. Draw the page a confirmation link opens, too (optional)
After somebody creates an account, the link in their confirmation email opens a page that confirms their address. You can draw that page as well — it is the first page a new customer sees.
-
Draw a screen — Address confirmed, say. There is nothing to type on it, so give the screen itself a load handler that confirms straight away:
confirmEmail("confirmed"); -
Put a "Checking your link…" line on it with Visible
!state.confirmed, and a "Your address is confirmed" message with a Sign in button in a stack with Visiblestate.confirmed. -
In the portal, choose it in Address-confirmed screen.
Your screen never sees the link's secret, exactly as on the new-password page. And a confirmation link only works once, so however many times your screen asks, the platform confirms once and gives every later ask the same answer. If the link has already been used or has expired, the visitor is told so in a message.
Leave Address-confirmed screen empty to keep the platform's own page. That page confirms the address and brings the visitor back to your Sign in screen with a message.
6. An address not confirmed yet, and a new password (optional)
Somebody who has not confirmed their address cannot sign in, and is told so. Give signIn a
fifth argument — the name of a state field — and it is set to true when that is the reason:
signIn(getState("email"), getState("password"), getState("code"), "needsCode", "unconfirmed");
With the field named, the platform shows no message of its own for this refusal — your drawing is the message, so draw the words as well as the button. Without it, the visitor is told in a message, as for any other refusal.
Draw a stack with Visible state.unconfirmed holding a Send the confirmation email again
button:
resendConfirmation(getState("email"), "resent");
resendConfirmation sets the field you name once asked, and — like the reset link — says "if there
is an account waiting to be confirmed", because the platform will not say whether there is. A
Resend confirmation screen with an email box and that button, open before signing in, serves
somebody who never tried to sign in.
A signed-in visitor can change their password on a screen behind the way in: the current one, the new one twice, and
changePassword(getState("current"), getState("password"));
Compare the two new ones in the handler first. On success the visitor is signed out everywhere and the portal takes them to your sign-in, with a message saying the password is set.
A signed-in visitor can change their name and photo, too. On their account page:
changeName(getState("name"), "renamed"); // "renamed" is set to true once it is saved
changePhoto(); // opens the device's picture chooser
removePhoto();
changePhoto() opens the visitor's own picture chooser, shrinks the picture in the browser and saves
it; if they cancel, nothing happens. Afterwards user.name and user.photo show the new ones, on
every screen. Where user.photo is empty, draw a placeholder rather than an empty picture.
7. Or place the sign-in kit instead of drawing it
The portal-sign-in-kit sample solution has every screen above already drawn, as components: a sign-in card, a create-account card, the account card with the name and photo, and two-step sign-in. Its app shares its components, so after you import it, every app in the environment finds them under Components → From other apps, whatever solution it is in.
A sample that places the cards does not need the kit imported. It carries its own copy of each card, which is why they are in its designer already. Import the kit when you want to place the cards in an app of your own, or to change them in one place.
Place a card on a screen and point its properties at your screen's state — email at
state.email, sent at state.sent. The card writes what is typed into those fields, and puts its
answers there too. Name your screens as the cards expect (Sign in, Create account, Forgot
password, Resend confirmation, New password, Address confirmed, Account, Change password,
Sign-in security) and the links between them work.
When the kit changes, open your app in the designer: it says its copies were brought up to date. Save it, and your portal has the change.
The portal-landing-page, portal-service-desk and portal-sign-in-and-accounts samples all place the kit this way.
What this does not do
- It does not change who can sign in. It is the same account, the same password rules and the same two-step sign-in as the platform's page.
- It does not work on a portal anyone can open. There is nobody to sign in, so the portal refuses a sign-in screen there.
Try it
Import the portal-sign-in-kit sample solution, then portal-landing-page. The landing page has the whole way in and an account page behind it, placed from the kit, and a How this sample works page that walks through it.