- On JavaScript/TypeScript platforms, make sure to pick a generic OIDC client library such as
@openid/AppAuth-JS
orangular-auth-oidc-client
. If you use some of the Ping-published libraries being used in their examples - such as@ping-identity/p14c-js-sdk-auth
- that depend on features specific to Ping's hosted environments, you would face issues when deploying against other environments like PingFederate.
- Ping hosted environments include the signing (JWT) public key - embedded in a X.509 certificate - in their JWKS endpoint responses (under a
x5j
field); but relying on that field would make your solution incompatible with other environments/providers, which may not contain this readily-usable field. Instead you can derive the key using the standard modulusn
and exponente
from the JWKS JSON:import java.security.spec.RSAPublicKeySpec; import org.springframework.util.Base64Utils; // key is a map containing JWKS spec RSAPublicKeySpec spec = new RSAPublicKeySpec( new BigInteger(1, Base64Utils.decodeFromUrlSafeString((String) key.get("n"))), new BigInteger(1, Base64Utils.decodeFromUrlSafeString(((String) key.get("e"))))); return keyFactory.generatePublic(spec);
- If you are developing specifically for the Ping hosted environment, using
@pingidentity/p14c-js-sdk-auth
, note these regarding single-page app (SPA) mode:- The library has non-standard parameters (e.g.
environment_id
, andAUTH_URL
/APP_URL
for environments hosted in non-.com
domains/regions) and conditions (e.g. environment and client IDs must be in UUID format). However other standard OIDC libraries can be used against the same environments without these additional parameters/constraints. - In implicit (token) grant, you can extract the token from the callback URL using
client.parseRedirectUrl()
followed byclient.tokenManager.get('idToken')
, which returns a Promise containing parsed URL data (having anidToken
or similar field). - When using PKCE under authorization code grant, you can extract the
code_verifier
used by the Ping client usingclient.tokenManager.pkce.loadData().codeVerifier
(for the code-to-token exchange phase).
- The library has non-standard parameters (e.g.
A typical implementation that supports both implicit and auth. code grants, in Angular, may look like:
import {PingOneAuthClient} from "@ping-identity/p14c-js-sdk-auth/dist/@ping-identity/p14c-js-sdk-auth"; type PingClient = { signIn(); signOut(); revokeToken(token, tokenName); parseRedirectUrl (options?); getUserInfo(); tokenManager: { get(tokenName: string): { value: string }; pkce: { loadData(): { codeVerifier: string } }; }; config: { responseType: Array<string> }; }; // from a typical Ping hosted environment const pingAuth = { "AUTH_URI": "https://auth.pingone.asia", "APP_URI": "https://app.pingone.asia", "environmentId": "your-env-id-uuid", "clientId": "your-client-id-uuid", "scopes": ["openid"], "responseType": ["id_token"], "storage": "localStorage", "pkce": false // make sure to revise, based on your security/compliance needs }; // .. component code; need Http, ActivatedRoute async getClient(): Promise<PingClient> { return new PingOneAuthClient({ ...pingAuth, redirectUri: `${window.location.origin}/openid-callback` // your callback URL }); } async initiateAuth() { return (await this.getClient()).signIn(); } async completeAuth() { const client = await this.getClient(); if (client.config.responseType.includes('id_token')) { // implicit return client.parseRedirectUrl() .then(() => client.tokenManager.get('idToken')) .then(token => token.idToken); } else { const code = this.route.snapshot.queryParams['code']; // auth.code let contentHeader: Headers = new Headers(); contentHeader.append("Content-Type", "application/json"); return this.http.post(/* your code-exchange backend URL */, JSON.stringify({ code, verifier: client.tokenManager.pkce.loadData().codeVerifier }), { headers: contentHeader }).toPromise() .then(response => response.json()['id_token']) // depends on your backend .catch(e => /* handle it */); }
No comments:
Post a Comment