Safeguard
Application Security•

ASVS 5.0 V10.7.1: Get User Consent for Each Authorization Request

The authorization server must make sure the user consents to every authorization request, and always prompt when the client's identity cannot be assured.

Safeguard Security Team
6 min read

ASVS 5.0 V10.7.1 (Level 2) says the authorization server must ensure that the user consents to each authorization request. When the identity of the client cannot be assured, the server must always show an explicit consent prompt.

Remembering a past approval is allowed for clients you can trust. The rule is about not treating "approved once" as "approved forever for anything that claims to be this app".

Why it matters

Consent is the point where a human decides to give an application access to their data. Skip it, and a malicious or compromised client can obtain tokens just by getting a logged in user to open a link. This is the core of consent phishing.

Client identity is the hard part. A client ID and a display name are public strings, and anyone can copy them. Redirect URIs registered by the owner and strong client authentication are real signals. Where the client is public, dynamically registered or unverified, the safe default is to prompt every time.

How to implement it

Decide per request whether prior consent can be reused. A conservative rule looks like this:

def needs_consent_prompt(user, client, requested_scopes, request):
    if request.params.get("prompt") == "consent":
        return True
    if not client.identity_assured:
        return True            # public, dynamic or unverified client
    prior = db.get_consent(user.id, client.id)
    if prior is None:
        return True
    if not set(requested_scopes) <= set(prior.scopes):
        return True            # new scopes need a new decision
    if prior.expires_at <= datetime.now(timezone.utc):
        return True
    return False

Define what "identity assured" means in your system. Examples: a first party app owned by you, a client registered by an administrator with exact redirect URIs, or a client that authenticates with a key. A client that registered itself through open dynamic registration is never in that group.

Protect the consent form itself:

  • Bind the consent submission to the user's session and to the exact pending request with a CSRF token and a request identifier.
  • Do not let the consent page be framed by other origins. Send Content-Security-Policy: frame-ancestors 'none' and X-Frame-Options: DENY so a hidden iframe cannot trick a click.
  • Store the decision server side with the scopes granted and a timestamp.

Consent also matters for tools that act for users. AI assistants and MCP servers often request access through OAuth. Safeguard's MCP guardrail demo shows how policy can sit between an agent and the tools it calls:

Click through it at your own pace, or open it full screen.

Prompt parameters

Honor the prompt parameter from OpenID Connect carefully. prompt=none means the client wants no user interface, so the server must answer with consent_required or login_required rather than showing a screen or granting silently. prompt=consent means the user must see the screen even if a prior grant exists.

Do not let a client downgrade the prompt for other clients. Consent records belong to the pair of user and client, never to the user alone.

Revocation of remembered consent

Give remembered consents an expiry, for example 30 to 90 days for lower risk scopes, and shorter for sensitive ones. When a client changes its registered redirect URIs or its owner, clear existing consents for it, because the thing the user approved is no longer the same thing.

How to test it

  1. Sign in as a user who has never authorized a test client. Start a flow and confirm a consent screen appears.
  2. Repeat with the same client and the same scopes. For a trusted first party client you may skip the prompt. For an unverified client, the prompt must appear again.
  3. Request an extra scope from a client that was approved before. A new prompt must show the added scope.
  4. Add prompt=none to the request for a client that needs consent. Expect an error such as consent_required, not a silent grant.
  5. Load the consent URL inside an iframe on another origin. The browser should refuse to render it.
  6. Post the consent form without a valid CSRF token, or from another session. Expect rejection.

Automating the check

Cover the prompt logic with unit tests on the decision function, then add two end to end checks: one for prompt=none returning an error, and one for the consent page returning framing protection headers.

curl -sI https://auth.example.com/consent | grep -iE "x-frame-options|content-security-policy"

Handling first party clients

Many teams have first party apps that share a login with the authorization server, and showing consent for them would annoy users with no gain. The requirement allows skipping the prompt when client identity is assured. Make that an administrator flag on the client record, record who set it and when, and review the list on a schedule. Treat any change to its redirect URIs as a trigger to review the flag.

Logging consent decisions

Record every consent decision with the user, the client, the scopes shown, the scopes granted and the time. When someone later asks why an app had access, you have an answer. These records also feed the review page in V10.7.3, where users see and revoke what they approved.

Common mistakes

  • Auto approving all clients on a corporate tenant because users are "internal". Internal users still get phished.
  • Trusting the client name or logo as proof of identity.
  • Storing consent per user but not per client and scope.
  • Allowing prompt=none to bypass a required decision.
  • Consent screens that can be clickjacked.

Quick check

When must the server always prompt?

Whenever the identity of the client cannot be assured, such as public, dynamically registered or unverified clients.

What should happen if a client asks for a new scope later?

The user should be asked again, because the earlier decision did not cover it.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.