This posts shows how an Angular application can be secured using Open ID Connect code flow with PKCE and OAuth Pushed Authorisation Requests using node-oidc-provider as the identity provider. This requires configuration on both the client and the identity provider.
Code: par-angular
Getting started using Schematics and angular-auth-oidc-client
The Angular client is implemented using angular-auth-oidc-client.
ng add can be used to add the auth bits to your project.
ng add angular-auth-oidc-client
Then select the configuration you require.
The auth-config.module is now created and the configuration can be completed as required. PAR is activated by using the usePushedAuthorisationRequests configuration. The offline_access scope is requested as well as the prompt=consent. The nonce validation after a refresh is ignored.
export function configureAuth(oidcConfigService: OidcConfigService) { return () => oidcConfigService.withConfig({ stsServer: 'http://localhost:3000', redirectUrl: window.location.origin, postLogoutRedirectUri: window.location.origin, clientId: 'client-par-required', usePushedAuthorisationRequests: true, // use par Pushed Authorisation Requests scope: 'openid profile offline_access', responseType: 'code', silentRenew: true, useRefreshToken: true, logLevel: LogLevel.Debug, ignoreNonceAfterRefresh: true, customParams: { prompt: 'consent', // login, consent }, }); }
The node-oidc-provider client configuration require_pushed_authorization_requests is set to true so that Pushed Authorisation Requests can be used. The node-oidc-provider clients need a configuration for the public client which uses refresh tokens. The grant_types ‘refresh_token’, ‘authorization_code’ are added as well as the offline_access scope. As this is still draft, you need to enable Pushed Authorisation Requests before you can use it.
clients: [ { client_id: 'client-par-required', token_endpoint_auth_method: 'none', application_type: 'web', grant_types: ['refresh_token', 'authorization_code'], redirect_uris: ['https://localhost:4207'], require_pushed_authorization_requests: true, scope: 'openid offline_access profile email', post_logout_redirect_uris: [ 'https://localhost:4207' ] }, ], features: { devInteractions: { enabled: false }, // defaults to true deviceFlow: { enabled: true }, // defaults to false introspection: { enabled: true }, // defaults to false revocation: { enabled: true }, // defaults to false pushedAuthorizationRequests: { enabled: true }, },
When the authentication begins, the well known endpoints is used to get the PAR endpoint. The property pushed_authorization_request_endpoint will be set if this is supported.
http://localhost:3000/.well-known/openid-configuration
{ "pushed_authorization_request_endpoint":"http://localhost:3000/request", "authorization_endpoint":"http://localhost:3000/auth", "token_endpoint":"http://localhost:3000/token" "issuer":"http://localhost:3000", "jwks_uri":"http://localhost:3000/jwks", "userinfo_endpoint":"http://localhost:3000/me", "introspection_endpoint":"http://localhost:3000/token/introspection", // ... more
The PAR request is sent using the same parameters as OIDC code flow, but in the body of the request. As this is a public client, the client is not authorized. This was also configured in the IDP.
client_id=client-par-required &redirect_uri=https://localhost:4207 &response_type=code &scope=openid profile offline_access &nonce=73a2f7 + ... &code_challenge=aLo8v3vvenGVmXwecG3-rhuYATGTrKBKnMmXHayXpHI &code_challenge_method=S256 &prompt=consent
All configured correctly, the PAR response will contain the url to the server session for this auth request.
{ expires_in: 300, request_uri: "urn:ietf:params:oauth:request_uri:oeSbJ-jn1QvsTW9EUsAasmypWj7-PQEp7RjxogiCWUo" }
The client then redirects to the authorization endpoint and the flow continues like the existing standard.
http://localhost:3000/auth? request_uri=urn%3Aietf%3Aparams%3Aoauth%3Arequest_uri%3AoeSbJ-jn1QvsTW9EUsAasmypWj7-PQEp7RjxogiCWUo &client_id=client-par-required
That’s all the configuration required. The OAuth Pushed Authorisation Requests is still in draft and so might change. Hopefully this will get rolled out and more identity providers will support this specification.
The next steps would be to use OAuth RAR in the PAR request.
Links:
https://github.com/panva/node-oidc-provider
https://github.com/damienbod/angular-auth-oidc-client
https://tools.ietf.org/html/draft-ietf-oauth-par-06
https://www.connect2id.com/products/server/docs/api/par
[…] Implementing OAuth Pushed Authorisation Requests in Angular – Damien Bowden […]
[…] Implementing OAuth Pushed Authorization Requests in Angular (Damien Bowden) […]