Skip to content
This repository was archived by the owner on Jul 2, 2026. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default {
}
},
'site-page': {},
'@apostrophecms/vite': {}
'@apostrophecms/vite': {},
'@apostrophecms/passport-bridge': {}
}
};
79 changes: 79 additions & 0 deletions dashboard/modules/@apostrophecms/passport-bridge/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import * as client from 'openid-client';
import {
Strategy
} from 'openid-client/passport'

export default {
options: {
create: {
role: 'guest'
},
strategies: [
{
async factory(params, fn) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New factory option allows us to pass our own async function that returns a fully initialized strategy object. This allows us to use OIDC discovery

const issuer = new URL(process.env.OIDC_ISSUER);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of discovery, all we need is a URL to the provider site (OIDC_ISSUER), OIDC_CLIENT_ID, and OIDC_CLIENT_SECRET.

const config = await client.discovery(
issuer,
process.env.OIDC_CLIENT_ID,
process.env.OIDC_CLIENT_SECRET
);
const {
// injected into params by passport-bridge
callbackURL
} = params;
const s = new Strategy({
config,
scope: 'openid email',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can beef this up if you have other scopes of interest.

callbackURL
}, (tokens, callback) => {
const claims = tokens.claims();

// oidc provides:

// sid
// name: 'Tom Boutell',
// preferred_username: 'tomtest1',
// given_name: 'Tom',
// family_name: 'Boutell',
// email: 'tom+tomtest1@apostrophecms.com'

// But oauth providers provide (and passport-bridge expects, by default):

// id
// displayname
// username
// firstName
// lastName
// "emails" or "email"

const profile = {
id: claims.sid,
displayName: claims.name,
firstName: claims.given_name,
lastName: claims.family_name,
email: claims.email,
username: claims.preferred_username
};

return fn(null, tokens.access_token, tokens.refresh_token, profile, callback);
});
// The strategy sets it to the hostname, override so we can predict the URLs
s.name = 'oidc';
return s;
},
// Required when using a factory function
name: 'oidc',
// These would show up in "params" above, we chose to use environment
// variables instead
options: {},
// Use the user's email address as their identity
match: 'email',
// Strategy-specific options that must be passed to the authenticate middleware.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you should be able to skip this "authenticate" property because it is covered by the factory function.

// See the documentation of the strategy module you are using
authenticate: {
scope: [ 'openid', 'email' ]
}
}
]
}
}
61 changes: 61 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@apostrophecms-pro/multisite-dashboard": "^1.4.0",
"@apostrophecms-pro/palette": "^4.3.2",
"@apostrophecms/favicon": "^1.1.2",
"@apostrophecms/passport-bridge": "1.5.0-beta.1",
"@apostrophecms/vite": "^1.0.0",
"@opentelemetry/auto-instrumentations-node": "^0.46.1",
"@opentelemetry/exporter-jaeger": "^1.26.0",
Expand All @@ -41,6 +42,7 @@
"apostrophe": "^4.9.0",
"glob": "^10.4.5",
"normalize.css": "^8.0.1",
"openid-client": "^6.6.2",
"swiper": "^11.1.3"
},
"devDependencies": {
Expand Down
8 changes: 7 additions & 1 deletion sites/modules/@apostrophecms/home-page/views/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@

{% block main %}
<section class="page-home">
<h1>User Info</h1>
<ul>
{% for name, value in data.user %}
<li>{{ name }}: {{ value }}</li>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just showing we get access.

{% endfor %}
</ul>
{% if data.theme === 'demo' %}
{% include 'theme-demo:welcome.html' %}
{% endif %}

{% area data.page, 'main' %}
</section>
{% endblock %}
{% endblock %}