Skip to content

Commit

Permalink
feat(oidc): add DPOP configuration (#1259) (release)
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaume-chervet committed Jan 26, 2024
1 parent df754bd commit b0510eb
Show file tree
Hide file tree
Showing 19 changed files with 408 additions and 255 deletions.
2 changes: 2 additions & 0 deletions examples/react-oidc-demo/public/OidcTrustedDomains.js

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

4 changes: 2 additions & 2 deletions examples/react-oidc-demo/src/FetchUser.tsx
Expand Up @@ -46,7 +46,7 @@ const UserInfoWithFetchHoc = withOidcFetch(fetch)(DisplayUserInfo);

export const FetchUserHoc = () => <OidcSecure><UserInfoWithFetchHoc/></OidcSecure>;

export const FetchUserHook = () => {
const { fetch } = useOidcFetch();
export const FetchUserHook = (props:any) => {
const { fetch } = useOidcFetch(window.fetch, props.configurationName);
return <OidcSecure><DisplayUserInfo fetch={fetch} /></OidcSecure>;
};
44 changes: 35 additions & 9 deletions examples/react-oidc-demo/src/MultiAuth.tsx
Expand Up @@ -8,6 +8,7 @@ import { CallBackSuccess } from './override/Callback.component';
import Loading from './override/Loading.component';
import ServiceWorkerNotSupported from './override/ServiceWorkerNotSupported.component';
import SessionLost from './override/SessionLost.component';
import {FetchUserHook} from "./FetchUser";

const fetchWithLogs = (fetch: Fetch) => async (...params: Parameters<Fetch>) => {
const [url, options, ...rest] = params;
Expand Down Expand Up @@ -45,6 +46,7 @@ const MultiAuth = ({ configurationName, handleConfigurationChange }) => {
<option value="config_with_hash">config_with_hash</option>
<option value="config_show_access_token">config_show_access_token</option>
<option value="config_separate_oidc_access_token_domains">config_separate_oidc_access_token_domains</option>
<option value="config_with_dpop">config_with_dpop</option>
</select>
{!isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => login()}>Login</button>}
{isAuthenticatedDefault && <button type="button" className="btn btn-primary" onClick={() => login(undefined, { 'test:token_request': 'test', youhou: 'youhou', grant_type: 'tenant', tenantId: '1234' }, true)}>Silent Login</button>}
Expand Down Expand Up @@ -118,6 +120,27 @@ export const MultiAuthContainer = () => {
redirect_uri: callBack,
silent_redirect_uri,
},
config_with_dpop: {
...configurationIdentityServer,
redirect_uri: callBack,
silent_redirect_uri,
demonstrating_proof_of_possession: true,
/*demonstrating_proof_of_possession_configuration: {
importKeyAlgorithm: {
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
},
signAlgorithm: { name: "RSASSA-PKCS1-v1_5" },
generateKeyAlgorithm: {
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048, //can be 1024, 2048, or 4096
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
},
digestAlgorithm: { name: "SHA-256" },
jwtHeaderAlgorithm: "RS256",
},*/
}
};
const handleConfigurationChange = (event) => {
const configurationName = event.target.value;
Expand Down Expand Up @@ -176,15 +199,18 @@ const DisplayAccessToken = ({ configurationName }) => {
return <p>you are not authentified</p>;
}
return (
<div className="card text-white bg-info mb-3">
<div className="card-body">
<h5 className="card-title">Access Token</h5>
<p style={{ color: 'red', backgroundColor: 'white' }}>Please consider to configure the ServiceWorker in order to protect your application from XSRF attacks. &quot;access_token&quot; and &quot;refresh_token&quot; will never be accessible from your client side javascript.</p>
{<p className="card-text">Access Token: {JSON.stringify(accessToken)}</p>}
{accessTokenPayload != null && <p className="card-text">Access Token Payload: {JSON.stringify(accessTokenPayload)}</p>}
<h5 className="card-title">Id Token</h5>
{idTokenPayload != null && <p className="card-text">Access Token Payload: {JSON.stringify(idTokenPayload)}</p>}
<>
<div className="card text-white bg-info mb-3">
<div className="card-body">
<h5 className="card-title">Access Token</h5>
<p style={{ color: 'red', backgroundColor: 'white' }}>Please consider to configure the ServiceWorker in order to protect your application from XSRF attacks. &quot;access_token&quot; and &quot;refresh_token&quot; will never be accessible from your client side javascript.</p>
{<p className="card-text">Access Token: {JSON.stringify(accessToken)}</p>}
{accessTokenPayload != null && <p className="card-text">Access Token Payload: {JSON.stringify(accessTokenPayload)}</p>}
<h5 className="card-title">Id Token</h5>
{idTokenPayload != null && <p className="card-text">Access Token Payload: {JSON.stringify(idTokenPayload)}</p>}
</div>
</div>
</div>
<FetchUserHook configurationName={configurationName} />
</>
);
};
31 changes: 31 additions & 0 deletions packages/oidc-client/README.md
Expand Up @@ -205,8 +205,37 @@ const configuration = {
monitor_session: Boolean, // Add OpenID monitor session, default is false (more information https://openid.net/specs/openid-connect-session-1_0.html), if you need to set it to true consider https://infi.nl/nieuws/spa-necromancy/
token_renew_mode: String, // Optional, update tokens based on the selected token(s) lifetime: "access_token_or_id_token_invalid" (default), "access_token_invalid", "id_token_invalid"
logout_tokens_to_invalidate: Array<string>, // Optional tokens to invalidate during logout, default: ['access_token', 'refresh_token']
location: ILOidcLocation, // Optional, default is window.location, you can inject your own location object respecting the ILOidcLocation interface
demonstrating_proof_of_possession: Boolean, // Optional, default is false, if true, the the Demonstrating Proof of Possession will be activated //https://www.rfc-editor.org/rfc/rfc9449.html#name-protected-resource-access
demonstrating_proof_of_possession_configuration: DemonstratingProofOfPossessionConfiguration // Optional, more details bellow
};


interface DemonstratingProofOfPossessionConfiguration {
generateKeyAlgorithm: RsaHashedKeyGenParams | EcKeyGenParams,
digestAlgorithm: AlgorithmIdentifier,
importKeyAlgorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm,
signAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams,
jwtHeaderAlgorithm: string
};

// default value of demonstrating_proof_of_possession_configuration
const defaultDemonstratingProofOfPossessionConfiguration: DemonstratingProofOfPossessionConfiguration ={
importKeyAlgorithm: {
name: 'ECDSA',
namedCurve: 'P-256',
hash: {name: 'ES256'}
},
signAlgorithm: {name: 'ECDSA', hash: {name: 'SHA-256'}},
generateKeyAlgorithm: {
name: 'ECDSA',
namedCurve: 'P-256'
},
digestAlgorithm: { name: 'SHA-256' },
jwtHeaderAlgorithm : 'ES256'
};


```

## API
Expand Down Expand Up @@ -374,6 +403,8 @@ More information about OIDC
- [French : Augmentez la sécurité et la simplicité de votre Système d’Information OpenID Connect](https://medium.com/just-tech-it-now/augmentez-la-s%C3%A9curit%C3%A9-et-la-simplicit%C3%A9-de-votre-syst%C3%A8me-dinformation-avec-oauth-2-0-cf0732d71284)
- [English : Increase the security and simplicity of your information system with openid connect](https://medium.com/just-tech-it-now/increase-the-security-and-simplicity-of-your-information-system-with-openid-connect-fa8c26b99d6d)
- [English: youtube OIDC](https://www.youtube.com/watch?v=frIJfavZkUE&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=1)
- [French: youtube OIDC](https://www.youtube.com/watch?v=H-mLMGzQ_y0&list=PL8EMdIH6Mzxy2kHtsVOEWqNz-OaM_D_fB&index=2)
## Hash route
Expand Down
3 changes: 2 additions & 1 deletion packages/oidc-client/src/checkSession.ts
@@ -1,9 +1,10 @@
import { CheckSessionIFrame } from './checkSessionIFrame.js';
import { _silentLoginAsync, SilentLoginResponse } from './silentLogin.js';
import { OidcConfiguration } from './types.js';
import Oidc from "./oidc";

// eslint-disable-next-line @typescript-eslint/ban-types
export const startCheckSessionAsync = (oidc:any, oidcDatabase:any, configuration :OidcConfiguration) => (checkSessionIFrameUri, clientId, sessionState, isSilentSignin = false) => {
export const startCheckSessionAsync = (oidc:Oidc, oidcDatabase:any, configuration :OidcConfiguration) => (checkSessionIFrameUri, clientId, sessionState, isSilentSignin = false) => {
const silentLoginAsync = (extras, state = undefined, scope = undefined):Promise<SilentLoginResponse> => {
return _silentLoginAsync(oidc.configurationName, configuration, oidc.publishEvent.bind(oidc))(extras, state, scope);
};
Expand Down
2 changes: 1 addition & 1 deletion packages/oidc-client/src/initSession.ts
Expand Up @@ -29,7 +29,7 @@ export const initSession = (configurationName, storage = sessionStorage) => {
storage[`oidc.nonce.${configurationName}`] = nonce.nonce;
};

const setDemonstratingProofOfPossessionJwkAsync = (jwk) => {
const setDemonstratingProofOfPossessionJwkAsync = (jwk:JsonWebKey) => {
storage[`oidc.jwk.${configurationName}`] = JSON.stringify(jwk);
};

Expand Down
2 changes: 1 addition & 1 deletion packages/oidc-client/src/initWorker.ts
Expand Up @@ -171,7 +171,7 @@ export const initWorkerAsync = async(configuration, configurationName) => {
return result.demonstratingProofOfPossessionNonce;
};

const setDemonstratingProofOfPossessionJwkAsync = async (demonstratingProofOfPossessionJwk:string) => {
const setDemonstratingProofOfPossessionJwkAsync = async (demonstratingProofOfPossessionJwk:JsonWebKey) => {
const demonstratingProofOfPossessionJwkJson = JSON.stringify(demonstratingProofOfPossessionJwk);
sendMessageAsync(registration)({ type: 'setDemonstratingProofOfPossessionJwk', data: { demonstratingProofOfPossessionJwkJson }, configurationName });
};
Expand Down

0 comments on commit b0510eb

Please sign in to comment.