- On JavaScript/TypeScript platforms, make sure to pick a generic OIDC client library such as
@openid/AppAuth-JSorangular-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
x5jfield); 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 modulusnand exponentefrom 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_URLfor environments hosted in non-.comdomains/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 anidTokenor similar field). - When using PKCE under authorization code grant, you can extract the
code_verifierused 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
Thanks for commenting! But if you sound spammy, I will hunt you down, kill you, and dance on your grave!