Advanced Portal Designer Documentation
Index

Authentication

APD provides built-in authentication for portal users, allowing secure access to protected content and personalized experiences.

Authentication Overview

How It Works

  1. User navigates to a protected action
  2. APD redirects to Login action
  3. User enters credentials
  4. APD validates against User table
  5. Session marked as authenticated
  6. User redirected to original action

Session Management

  • Sessions stored in APD Session table
  • Session ID passed via cookie or URL
  • Sessions have configurable timeout
  • Authentication state persists across requests

Login Action Setup

Creating a Login Action

  1. Create a new action
  2. Set Login Action = Yes
  3. Create the login template
  4. Compile the action

Login Action Properties

Property Value
Login Action Yes
Require Authentication No
Type HTML or Html Script

Login Template

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <div class="login-container">
        <h1>Login</h1>

        <!-- <?loginerror?> outputs the login error message (empty when no error). -->
        <div class="error"><?loginerror(.)?></div>

        <form method="post">
            <input type="hidden" name="action" value="LOGIN">

            <div class="field">
                <label>Username</label>
                <input type="text" name="username" required autofocus>
            </div>

            <div class="field">
                <label>Password</label>
                <input type="password" name="password" required>
            </div>

            <button type="submit">Login</button>
        </form>

        <div class="links">
            <a href="<?action(FORGOT-PASSWORD)?>">Forgot Password?</a>
            <a href="<?action(REGISTER)?>">Create Account</a>
        </div>
    </div>
</body>
</html>

APD does not provide <?if(userblocked)?> or any other built-in user-blocked tag in the template language. The login flow itself enforces the lockout: when a user has been blocked, the next login attempt fails and the message is carried in <?loginerror?> — there is no separate template branch to render. If you need a custom "account locked" page, send the user there from a Codeunit or Script action after detecting the block.

Form Parameters

Required Parameters

Parameter Description
username User's login ID or email
password User's password
action The login action code

Optional Parameters

Parameter Description
company Company code (multi-company)
actionurl Return action after login
email Alternative to username

Password Handling

Password Storage

  • Passwords are never stored in plain text
  • Hashed using secure algorithm
  • Hash stored in "Hashed Password" field

Password Validation

  1. User enters password
  2. APD hashes the input
  3. Compared against stored hash
  4. Match = success, no match = failure

Password Attempts

  • Failed attempts tracked per user
  • Configurable maximum attempts
  • User locked after max attempts

Login Process Flow

┌──────────────┐
│ User submits │
│ login form   │
└──────┬───────┘
       ▼
┌──────────────┐
│ APD receives │
│ credentials  │
└──────┬───────┘
       ▼
┌──────────────┐     No      ┌──────────────┐
│ User exists? ├────────────►│ Show error   │
└──────┬───────┘             │ Wrong userid │
       │ Yes                 └──────────────┘
       ▼
┌──────────────┐     Yes     ┌──────────────┐
│ User blocked?├────────────►│ Show blocked │
└──────┬───────┘             │ message      │
       │ No                  └──────────────┘
       ▼
┌──────────────┐     No      ┌──────────────┐
│ Password     ├────────────►│ Increment    │
│ matches?     │             │ attempts     │
└──────┬───────┘             └──────────────┘
       │ Yes
       ▼
┌──────────────┐
│ Create       │
│ session      │
└──────┬───────┘
       ▼
┌──────────────┐
│ Redirect to  │
│ requested    │
│ action       │
└──────────────┘

Logout

Logout Action

Create a logout action or use built-in logout:

<a href="<?action(LOGOUT)?>">Logout</a>

Logout Process

  1. Session cleared
  2. Authentication state removed
  3. User redirected to default action

Logout Template

APD does not provide a <?redirect?> template tag. The <?logout?> tag invalidates the session, and the configured Login Action handles unauthenticated users on subsequent requests. A typical post-logout template just confirms and offers a path back to login:

<?logout?>
<h1>You have been logged out</h1>
<a href="<?action(LOGIN)?>">Login Again</a>

Session Information

Available in Templates

Tag Description
<?userid?> Logged-in user ID
<?company?> User's company
<?sessionid?> Current session ID
<?no?> User's BC entity number
<?usertype(N)?>...<?endif?> Conditional block — opens only when the session's BC Type matches N (1=Customer, 2=Vendor, 3=Contact, 4=Sales Person). There is no separate <?navisiontype?> tag.

Authentication Check

<?auth?>
    <p>Welcome, <?userid?>!</p>
<?else?>
    <a href="<?action(LOGIN)?>">Please login</a>
<?endif?>

Multi-Company Login

Company Selection

If multiple companies are available:

<form method="post">
    <input type="text" name="username" required>
    <input type="password" name="password" required>
    
    <select name="company">
        <option value="CRONUS">CRONUS International</option>
        <option value="FABRIKAM">Fabrikam Inc</option>
    </select>
    
    <button type="submit">Login</button>
</form>

Company from User

If user is assigned to specific company, company selection is not needed.

Email Login

Using Email Instead of Username

APD supports email-based login:

<input type="email" name="email" placeholder="your@email.com">

APD will look up the user by email field.

Remember Return URL

Capturing Return URL

You don't enforce login from inside the template — set Require Authentication on the action card instead. When an unauthenticated user hits that action, APD redirects to the configured Login Action and remembers the original action URL in the session (actionurl parameter). After successful login, APD returns the user to the original action automatically; no template-level redirect is needed.

Using Return URL

If your login template needs to preserve a return target (e.g. for a custom flow), pass it through a hidden field bound to the existing actionurl parameter:

<!-- In login template -->
<input type="hidden" name="actionurl" value="<?parm(actionurl)?>">

Error Messages

Available Error Information

Tag Description
<?loginerror?> Login error message — empty when no error is set; when called with a second argument like <?loginerror(.)?> returns the actual Session."Error Status Text".

There is no <?errortext?> tag or errortext() expression function — APD surfaces login errors through <?loginerror?> only.

Error Display

<?loginerror?> already returns empty when there is no error, so a guard <?if?> is unnecessary. The cleanest pattern is to render the surrounding element unconditionally and use CSS to hide it when its content is empty:

<div class="alert alert-danger"><?loginerror(.)?></div>

Lockout state is not exposed as a separate template flag. After a failed login attempt — including a "user is locked out" failure — <?loginerror?> carries the user-facing reason.

Security Considerations

Password Security

  • Use strong password requirements
  • Implement password reset flow
  • Consider password expiration policies

Brute Force Protection

  • Configure maximum password attempts
  • Implement account lockout
  • Consider CAPTCHA after failures

Session Security

  • Use HTTPS for all traffic
  • Implement session timeout
  • Clear sessions on logout

CSRF Protection

  • Include CSRF tokens in forms
  • Validate tokens on submit

Best Practices

User Experience

  • Clear error messages
  • Show remaining attempts
  • Provide password reset option
  • Remember intended destination

Security

  • Always use HTTPS
  • Don't expose user enumeration
  • Log authentication events
  • Implement rate limiting

Maintenance

  • Review locked accounts
  • Monitor failed attempts
  • Update password policies