-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add demonstrating proof of possession #1461
Add demonstrating proof of possession #1461
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1461 +/- ##
==========================================
+ Coverage 80.53% 81.24% +0.71%
==========================================
Files 45 46 +1
Lines 1731 1850 +119
Branches 344 366 +22
==========================================
+ Hits 1394 1503 +109
- Misses 299 306 +7
- Partials 38 41 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Will work on getting the code coverage up over the next week or so. |
I am thinking about if it makes sense to add an extended userStore for dpop. Within that store we could handle/ isolate stuff like export class DPopStorageStateStore extends WebStorageStateStore {
// ... handles indexeddb stuff and dpop related things needed to be done differently than without dpop
}
``` |
Okay, I had a Quick Look... When you say extend the WebStorageStateStore class, what benefit do we get from this? Because we are dealing with the CryptoKeyPair type when dealing with IndexedDb (this is the type required to be able to store the key material as non extractable and also the type/supertype used by the crypto.subtle library), we can't override the set, get, remove and getAllKeys methods on the class because the StateStore interface specifies the types <string | null>. So adding additional methods, such as getDPoPKeyPair is fine, but we don't really need the methods set, get, etc that are exposed by WebStorageStateStore because we don't need the session/local storage for anything DPoP currently (we might do if/when we add support for server side nonces though). We could change the StateStore interface to allow for CyptoKeyPair, e.g. something like:
And implement that interface directly e.g. Anyway, I suppose I'm not fully clear on what you are after as far as extending the WebStorageStateStore class. |
I was more thinking about this: your MR: public async removeUser(): Promise<void> {
const logger = this._logger.create("removeUser");
await this.storeUser(null);
logger.info("user removed from storage");
if (this.settings.dpopSettings.enabled) {
await IndexedDbCryptoKeyPairStore.remove("oidc.dpop");
logger.debug("removed dpop cyptokeys from storage");
}
await this._events.unload();
} idea: public async removeUser(): Promise<void> {
const logger = this._logger.create("removeUser");
await this.storeUser(null);
logger.info("user removed from storage");
/* not needed, as its part of the new `userStore` and done automatically removed when calling "await this.storeUser(null);"
if (this.settings.dpopSettings.enabled) {
await IndexedDbCryptoKeyPairStore.remove("oidc.dpop");
logger.debug("removed dpop cyptokeys from storage");
}*/
await this._events.unload();
}
// untested pseudo code only
export class DPopStorageStateStore extends WebStorageStateStore {
public async remove(key: string): Promise<string | null> {
const ret = super.remove(key);
await IndexedDbCryptoKeyPairStore.remove("oidc.dpop");
return ret;
}
...
} |
Okay, yep - and would you like to try and apply the same idea to all the methods on the WebStorateStateStore class - e.g. set, get, getAllKeys such that it can handle DPoP related data as well as the usual user attributes stored in local/session storage? |
if possible yes. the idea is to simplify the dpop code paths and the not dpop code paths.
public async dpopProof(url: string, httpMethod?: string): Promise {
|
d7206bb
to
c3ecaaf
Compare
So I gave this a go but it's not possible to extend the WebStorageStateStore class with a DPoPStorageStateStore class without changing the types on the WebStorageState class (and the interface) to allow returning a CryptoKeyPair on the get method... which seems a bit gross, e.g.
doesn't work unless I change the signature of the parent WebStorageStateStore class to also return One option might be to alter the WebStorateStateStore to handle DPoP as well as what it already does (we'd still need to alter the StateStore interface). What do you think? |
Maybe by adding a "new/additional" get like |
Ok, I have had a rough go at adding a DPoPStorageStateStore for you to look at. I altered the StateStore interface to accept the CryptoKeyPair type, hopefully that makes sense. Also added the additional getDPoP method and inject the instance of the store into the DPoPService now. Have a look and let me know what you think. If you're happy with the approach, I will move the IndexedDBCryptoKeyPairStore logic directly into the DPoPStorageStateStore and incorporate any other feedback you may have. I'll be travelling for the next few weeks so may not be able to do too much until May 👍 |
I will have a deeper look at this in the next days. Thanks for keeping up on this. |
Cool - I am back from travelling so can start working on this again when you have had a look 👍 |
Any thoughts on the latest commit @pamapa ? I am keen to progress this. |
Was busy the last weeks, I have checked out your branch and I am now looking at this code and have some thoughts and time in the future to work with you... General design
DPoPService:
DPoPStorageStateStore/IndexedDbCryptoKeyPairStore:
DPoPSettings:
Something like: let dpopJkt: string | undefined;
if (this.settings.dpop && this.settings.dpop.bind_authorization_code) {
const keys = await this.settings.dpop.store.get();
dpopJkt = await CryptoUtils.generateDPoPJkt({ keys });
} |
Thank you for the detailed feedback @pamapa, that is excellent and exactly what I was looking for. At a glance, that all makes sense and I will update this PR accordingly over the next week. One minor clarifying implementation question for you regarding the new |
If we create a new storage type we have some flexibility. I guess when we decouple from |
Looks awesome, its very close to be merged. I have found some little style stuff (see above & below). Thanks a lot for being patient and taking care! Question:
|
I see what you are saying: we would just need to be clear that an implementation of the As far as overall build size goes, there is a 5kb difference between master and this branch when I bundle it EDIT: I can confirm that changing the I've also fixed all the style issues you high lighted. Would like me to add some documentation regarding the feature and how to use it to this PR? |
We can explicitly throw an exception if the store is undefined, despite the type would enforce to not be undefined. Maybe hidden in the settings class...
Would be nice if you could add a new section in the docs/index.md. This can also be done in a next MR when this one has been merged... |
No problem, happy to do the docs in a different PR. For now I have annotated the I have also updated with main and added a check in |
Thanks for contributing! |
Thank you for the contribution. I noticed in your comments you removed the nonce option. We implement it here within our organization. Is it possible you could add the nonce back in? We get past the DPoP Proof but then are warned we need to supply the nonce value. Can you provide me some help or a workaround? Any help is greatly appreciated and I do thank you for the contribution. |
Hi there, yes I originally added a rough implementation but opted to remove it in favour of adding it in a separate PR (the PR was getting quite large, there was disagreement regarding the implementation and it is optional in the spec). I will open another PR next week. Perhaps you would be willing to help test and review it? |
Thank you once again, great work! I found your oidc-client-context and was able to get it working in my code. But got stuck on the DPoP nonce requirement. Yes absolutely I can test it and help anyway I can. Again, appreciate your work and the author of the library - great work ! For reference we are using OIDC+PKCE, with DPoP Proof and Nonce. From the auth0 and okta articles I was reading on the implementation while the Nonce is mentioned as optional I suspect most providers will use it to enhance security. |
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [oidc-client-ts](https://github.com/authts/oidc-client-ts) | dependencies | minor | [`3.0.1` -> `3.1.0`](https://renovatebot.com/diffs/npm/oidc-client-ts/3.0.1/3.1.0) | --- ### Release Notes <details> <summary>authts/oidc-client-ts (oidc-client-ts)</summary> ### [`v3.1.0`](https://github.com/authts/oidc-client-ts/releases/tag/v3.1.0) [Compare Source](authts/oidc-client-ts@v3.0.1...v3.1.0) oidc-client-ts v3.1.0 is a minor release. No longer using `crypto-js` package, but built-in browser [crypto.subtle](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle) module. Crypto.subtle is available only in [secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) (HTTPS). Also have a look into the [migration](https://github.com/authts/oidc-client-ts/blob/main/docs/migration.md) info. #### Changelog: - Fixes: - [#​1666](authts/oidc-client-ts#1666): fix link in docs to issue - [#​1600](authts/oidc-client-ts#1600): updated docs about logger - [#​1589](authts/oidc-client-ts#1589): fix compiler error for target=ES2022 - [#​1539](authts/oidc-client-ts#1539): fix small typo in `signinCallback` doc in UserManager.ts - [#​1504](authts/oidc-client-ts#1504): typo in sample app config - [#​1490](authts/oidc-client-ts#1490): fix the return type of `signinCallback` - [#​1443](authts/oidc-client-ts#1443): fixes typos in docs - Features: - [#​1672](authts/oidc-client-ts#1672): make `signoutCallback` return signout response if request_type is so:r - [#​1626](authts/oidc-client-ts#1626): add `popupSignal` property to `signinPopup` and `signoutPop` - [#​1580](authts/oidc-client-ts#1580): add dpop docs - [#​1569](authts/oidc-client-ts#1569): add dpop nonce support - [#​1457](authts/oidc-client-ts#1457): add extra headers - [#​1461](authts/oidc-client-ts#1461): add demonstrating proof of possession - [#​1430](authts/oidc-client-ts#1430): add global `requestTimeoutInSeconds` setting - [#​1405](authts/oidc-client-ts#1405): allow using default scopes from authorization server thanks to [@​klues](https://github.com/klues), [@​smujmaiku](https://github.com/smujmaiku), [@​mftruso](https://github.com/mftruso), [@​peetck](https://github.com/peetck), [@​dbfr3qs](https://github.com/dbfr3qs), [@​mottykohn](https://github.com/mottykohn), [@​noshiro-pf](https://github.com/noshiro-pf), [@​dbfr3qs](https://github.com/dbfr3qs), [@​grjan7](https://github.com/grjan7) and [@​natergj](https://github.com/natergj) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC4xMDkuMCIsInVwZGF0ZWRJblZlciI6IjM4LjEwOS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=--> Reviewed-on: https://git.tristess.app/alexandresoro/ouca/pulls/191 Reviewed-by: Alexandre Soro <[email protected]> Co-authored-by: renovate <[email protected]> Co-committed-by: renovate <[email protected]>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [oidc-client-ts](https://github.com/authts/oidc-client-ts) | dependencies | minor | [`3.0.1` -> `3.1.0`](https://renovatebot.com/diffs/npm/oidc-client-ts/3.0.1/3.1.0) | --- ### Release Notes <details> <summary>authts/oidc-client-ts (oidc-client-ts)</summary> ### [`v3.1.0`](https://github.com/authts/oidc-client-ts/releases/tag/v3.1.0) [Compare Source](authts/oidc-client-ts@v3.0.1...v3.1.0) oidc-client-ts v3.1.0 is a minor release. No longer using `crypto-js` package, but built-in browser [crypto.subtle](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle) module. Crypto.subtle is available only in [secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) (HTTPS). Also have a look into the [migration](https://github.com/authts/oidc-client-ts/blob/main/docs/migration.md) info. #### Changelog: - Fixes: - [#​1666](authts/oidc-client-ts#1666): fix link in docs to issue - [#​1600](authts/oidc-client-ts#1600): updated docs about logger - [#​1589](authts/oidc-client-ts#1589): fix compiler error for target=ES2022 - [#​1539](authts/oidc-client-ts#1539): fix small typo in `signinCallback` doc in UserManager.ts - [#​1504](authts/oidc-client-ts#1504): typo in sample app config - [#​1490](authts/oidc-client-ts#1490): fix the return type of `signinCallback` - [#​1443](authts/oidc-client-ts#1443): fixes typos in docs - Features: - [#​1672](authts/oidc-client-ts#1672): make `signoutCallback` return signout response if request_type is so:r - [#​1626](authts/oidc-client-ts#1626): add `popupSignal` property to `signinPopup` and `signoutPop` - [#​1580](authts/oidc-client-ts#1580): add dpop docs - [#​1569](authts/oidc-client-ts#1569): add dpop nonce support - [#​1457](authts/oidc-client-ts#1457): add extra headers - [#​1461](authts/oidc-client-ts#1461): add demonstrating proof of possession - [#​1430](authts/oidc-client-ts#1430): add global `requestTimeoutInSeconds` setting - [#​1405](authts/oidc-client-ts#1405): allow using default scopes from authorization server thanks to [@​klues](https://github.com/klues), [@​smujmaiku](https://github.com/smujmaiku), [@​mftruso](https://github.com/mftruso), [@​peetck](https://github.com/peetck), [@​dbfr3qs](https://github.com/dbfr3qs), [@​mottykohn](https://github.com/mottykohn), [@​noshiro-pf](https://github.com/noshiro-pf), [@​dbfr3qs](https://github.com/dbfr3qs), [@​grjan7](https://github.com/grjan7) and [@​natergj](https://github.com/natergj) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC4xMTAuMiIsInVwZGF0ZWRJblZlciI6IjM4LjExMC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=--> Reviewed-on: https://git.tristess.app/alexandresoro/ouca/pulls/196 Reviewed-by: Alexandre Soro <[email protected]> Co-authored-by: renovate <[email protected]> Co-committed-by: renovate <[email protected]>
This is the second part of splitting up #1361 - hopefully it is easier to review.
Addresses/highlights #1360
As per the issue, this is an implementation of Demonstrating Proof of Possession (DPoP) to constrain access/refresh tokens to devices.
This is mostly spec complete - though I have left out some parts that I don't think are appropriate to the oidc-client-ts use case (such as Pushed Authorisation Requests). I have also left out support for Authorization Server supplied nonces, which I would like to address in a separate PR in the future (this is optional in the spec).
I've used the react-odic-client library example app and npm linked it to my local version of this PR. I used a fork of IdentityServer's DPoP examples to develop and test against, if you are interested in trying it out for yourself.
Things of note:
Checklist