Consent screen
This is the one piece you need to host yourself: a page, on your own domain, that the third-party app's user is sent to in order to log in and approve (or deny) the connection.
Embed the widget
Paste this on the page you want to act as your consent screen, and tell the connecting app the URL of that page (see below):
<div id="{{block's reference ID}}"></div>
<script type="text/javascript">
var configuration = {
referenceId: '{{block's reference ID}}',
type: 'authorization',
authType: 'auth2',
theme: 'dark',
success: (data) => {
console.log('success response', data);
},
failure: (error) => {
console.log('failure reason', error);
},
};
</script>
<script
type="text/javascript"
onload="initVerification(configuration)"
src="https://36blocks.com/assets/proxy-auth/proxy-auth.js"
></script>
Replace {{block's reference ID}} with your block's reference ID (the same one you already use for ordinary login/signup widgets). authType: 'auth2' is what switches this into OAuth consent mode instead of a plain login widget.
The success/failure callbacks are not used for the OAuth outcome. They're only for the plain login/signup paths this same widget also supports elsewhere. Once your user approves or denies, the widget navigates the browser directly to the connecting app's own redirect_uri. There is nothing for your page's JavaScript to handle after that point.
What the connecting app needs to send
The third-party app builds a link to your consent screen page's URL (the one with the snippet above) and sends your user's browser there with its OAuth request appended as query parameters. The widget reads these directly from the page URL, not from anything in the configuration object:
Param | Required | Notes |
|---|---|---|
| always | From the OAuth Config you created. |
| always | Must exactly match one of the URIs you registered for that config. |
| always | Must be the literal value |
| optional | Space-separated list, e.g. |
| required for public clients (and any confidential client with Require PKCE turned on) | See PKCE, below. |
| required alongside | Must be exactly |
| recommended | Opaque value of the connecting app's own choosing, echoed back unchanged on the final redirect. Standard practice for the connecting app to detect CSRF, not something you need to do anything with yourself. |
Example link a third-party app might send your user to:
https://your-app.example.com/connect?client_id=aZ9k...&redirect_uri=https%3A%2F%2Ftheirapp.example.com%2Fcallback&response_type=code&scope=profile%20email
If any of these are missing or invalid (unknown client_id, a redirect_uri that isn't registered, etc.), the widget shows a plain error message and stops. It never guesses or redirects anywhere in that case, since the destination hasn't been verified yet.
PKCE
If PKCE is required for the config being used, the connecting app (not your widget, not your backend) is responsible for generating the PKCE pair, before it ever sends the user to your consent screen:
Generate a random
code_verifier(a high-entropy string, 43-128 characters per RFC 7636).Compute
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier)).Send
code_challengeandcode_challenge_method=S256as part of the link to your consent screen (table above).Hold onto the original
code_verifier. It's sent later, to the token endpoint, to prove it's the same app that started the flow (see Token endpoint).
Your widget and your backend never see or generate code_verifier. They only ever see and check code_challenge.
What happens on your consent page
The widget validates the incoming request. On failure: a static error, nothing else happens.
On success, your user sees your normal login/signup screen. Whichever login methods you already have enabled for this block (password, social login, OTP, etc.) all work exactly as they do anywhere else; nothing about them changes for OAuth.
Once logged in, a consent screen appears showing the connecting app's name and the scopes it requested, with Allow / Deny actions.
Approve or deny sends the browser to the connecting app's
redirect_uri:Approve →
redirect_uri?code=...&state=...Deny →
redirect_uri?error=access_denied&state=...
From here, everything happens on the connecting app's own backend. See Token endpoint.