-
Notifications
You must be signed in to change notification settings - Fork 75
Training: Mobile Authn
High level overview of the goals of this project: chain of custody from App Store to authz decision.
Using an SSA to obtain client credentials.
- The app distribution includes the SSA (Software Statement Assertion) generated from the Jans Auth Server, which is used for Dynamic Client Registration against the Auth Server.
- DCR attestation ensures that only legitimate and trusted clients can register with an authorization server. To use attestation in OAuth 2.0 Dynamic Client Registration, the app generates evidence in JWT format containing verifiable claims like app_id and app-checksum.
- For Android applications, the integrity verdict from the Play Integrity API can be added as a claim in the evidence JWT for attested DCR. This claim is then verified by the designated verifier to ensure the trustworthiness of both the app and the Android device. Based on this verification, the DCR is either approved or rejected.
- The public key used for signing the attested JWT must also be included in the attested Dynamic Client Registration request, so it can be verified by the Jans Auth Server. A sample DCR request on Jans Auth Server is as follows:
########
Request
########
curl -X POST -k -H ‘Content-Type: application/json' -i ‘https://your.janssen.server/jans-auth/restv1/register' — data ‘{
"software_statement": "eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7ImUiOiJBUUFCIiwia3R5IjoiUlNBIiwibi.......thMdKlqynrn9kyLXwflpMWbirWrQxIpIbkQ6srHStyDDh1zBEyYNAj-pXz9iyhHULoz0Ig",
"client_name":"DPoPAppClient-bc041d99–2c02–4622–8b6b",
"evidence":"eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7ImUiOiJBUUFCIiwia3R5IjoiUlNBIiwibi.......thMdKlqynrn9kyLXwflpMWbirWrQxIpIbkQ6srHStyDDh1zBEyYNAj-pXz9iyhHULoz0Ig",
"jwks":"{\"keys\":[{\"e\":\"AQAB\",\"kty\":\"RSA\",\"n\":\"pzVIV71wHi1fG3TEcCUJw0uolOBUryEJPy8IFpI20lAWqWw5prPn2mPqsyaOPpQtNX2_12PmZjlDq3SjInipSK_saSJ4pm-LCTOYZm55n5QbiK-iCR0DgCVlAeNj6YIenk1Tdy0KSuYoZxOL7iOdMAT9f7qvRAlSdWivOef_tDEtCIbZ3aKoNujv0xPUmOgnZ0U1QdxK3bmprV08O6dV6-_GJBeEdGZ5qZezPIxyjaxiGcoDk47QxdFz-aD38md-zQDEr9toU08j08bgeZLvbVr5e_M-fzhGY5yEISg1e-87n_v3HbdKFGuRFqYp3CYVayuYMWJsIIq8aEPZxdi8qw\"}]}",
"redirect_uris":["https://your.janssen.server"],
"response_types":["code"],
"scope":"openid"
"application_type":"native"
}'
########
Response
########
{
"allow_spontaneous_scopes": false,
"jwks": {
"keys": [{
"kty": "RSA",
"e": "AQAB",
"n": "pzVIV71wHi1fG3TEcCUJw0uolOBUryEJPy8IFpI20lAWqWw5prPn2mPqsyaOPpQtNX2_12PmZjlDq3SjInipSK_saSJ4pm-LCTOYZm55n5QbiK-iCR0DgCVlAeNj6YIenk1Tdy0KSuYoZxOL7iOdMAT9f7qvRAlSdWivOef_tDEtCIbZ3aKoNujv0xPUmOgnZ0U1QdxK3bmprV08O6dV6-_GJBeEdGZ5qZezPIxyjaxiGcoDk47QxdFz-aD38md-zQDEr9toU08j08bgeZLvbVr5e_M-fzhGY5yEISg1e-87n_v3HbdKFGuRFqYp3CYVayuYMWJsIIq8aEPZxdi8qw"
}]
},
"application_type": "web",
"rpt_as_jwt": false,
"registration_client_uri": "https://your.janssen.server/jans-auth/restv1/register?client_id=05fd2650-8478-4bca-9488-b14f7219473b",
"tls_client_auth_subject_dn": "",
"run_introspection_script_before_jwt_creation": false,
"registration_access_token": "872ab5ca-457a-4118–95cf-d699dc549967",
"client_id": "05fd2650–8478–4bca-9488-b14f7219473b",
"token_endpoint_auth_method": "client_secret_basic",
"scope": "openid",
"client_secret": "97c734ca-a729–49b7–9ec3–514e43ba530b",
"client_id_issued_at": 1693571537,
"backchannel_logout_uri": [],
"backchannel_logout_session_required": false,
"client_name": "DPoPAppClient-bc041d99–2c02–4622–8b6b",
"par_lifetime": 600,
"spontaneous_scopes": [],
"id_token_signed_response_alg": "RS256",
"access_token_as_jwt": false,
"grant_types": ["authorization_code"],
"subject_type": "pairwise",
"additional_token_endpoint_auth_methods": [],
"keep_client_authorization_after_expiration": false,
"require_par": false,
"redirect_uris": ["https://your.janssen.server"],
"redirect_uris_regex": "",
"additional_audience": [],
"frontchannel_logout_session_required": false,
"client_secret_expires_at": 0,
"access_token_signing_alg": "RS256",
"response_types": ["code"]
}
How to do a multi-step backchannel authn flow.
After successful Dynamic Client Registration (DCR), the app saves the OIDC client details in the SQLite database. Each time the user opens the app, it checks for these details and, if present, proceeds directly to the passkey enrollment page where the user submits username and password to continue with the backchannel authentication flow using the Authorization Challenge Endpoint.
The Authorization Challenge Endpoint allows a first-party native client to obtain an authorization code, which can then be exchanged for an access token, enabling a fully browserless OAuth 2.0 experience for native applications. This endpoint adheres to the OAuth 2.0 for First-Party Native Applications specifications.
########
Request
########
curl -k https://your.janssen.server/jans-auth/restv1/authorization_challenge -d 'username=admin' -d 'password=secret' -d 'state=0x74ab847000' -d 'nonce=8974ab847000' -d 'client_id=05fd2650–8478–4bca-9488-b14f7219473b' -d 'auth_method=enrol'
########
Response
########
{"authorization_code":"cdf09c4a-10f4–467e-9f6f-a697db44b108"}
Auth Server provides AuthorizationChallengeType custom script which must be used to control Authorization Challenge Endpoint behavior. During user enrollment in aap, username and password verification is expertly guided by the Authorization Challenge script. The script has been enhanced to incorporate passkey verification during the enrolled user's authentication process. Include an authMethod parameter with values enrol or authenticate in the Authorization Challenge request. This allows the custom script to decide whether to enroll the user (executing username/password verification) or authenticate the user (executing passkey verification).
How to register (new user) using passkeys or authenticate.
- The mobile application distribution includes the SSA (Software Statement Assertion) generated from the Janssen Auth Server. The application reads OpenID and FIDO issuers from the SSA.
- & 3. The application fetches OpenID and FIDO configurations to the mobile database.
- To mitigate the risk of app tampering and the use of fraudulent devices, the integrity of the app and device, for Android applications can be verified using the Play Integrity API.
- The application performs DCR (Dynamic Client Registration) against the Auth Server using the SSA. To use attestation in OAuth 2.0 Dynamic Client Registration, the app generates evidence in JWT format containing verifiable claims like app_id and app-checksum. The integrity verdict from the Play Integrity API can be added as a claim in the evidence JWT for attested DCR. This claim is then verified by the designated verifier to ensure the trustworthiness of both the app and the Android device. Based on this verification, the DCR is either approved or rejected.
- Once the application is loaded, it shows the enrollment screen where the user can submit their username/password (for users already registered on the auth server). The app requests the Janssen Auth server's Authorization Challenge Endpoint to exchange an authorization code for the correct username/password. The Janssen auth server provides an AuthorizationChallengeType custom script which is used to control Authorization Challenge Endpoint behavior. During user enrollment in the app, username and password verification is expertly guided by the Authorization Challenge script.
- After verifying the username/password, the app calls the Janssen FIDO Server's /attestation/options endpoint with the username, displayname, and attestation (none) request parameters. The Janssen FIDO Server returns information about the user, the RP, and the type of credential desired.
- To perform user verification, the mobile app requests the user's fingerprint impression.
- On successful fingerprint verification, the authenticator library inside the app creates a new asymmetric key pair and safely stores the private key. The public key, a credential ID, and other attestation data are converted to an attestationObject by the authenticator.
- The app calls the Janssen FIDO Server's /attestation/reult endpoint with the attestationObject and clientDataJSON (a byte array containing the challenge sent by the RP, the origin of the domain observed by the client, and the type of operation performed) request parameters. The Janssen FIDO Server verifies the request and sends the success/failure response.
- Using the authorization code obtained in step #6, the app requests an access token from the Janssen Auth Server using the token endpoint. The token is of type DpoP.
- Using the access token, user info is fetched from the Janssen Auth Server, and the user details page is shown on the app with the user info.
- The mobile application displays already enrolled passkeys with it. On selecting a passkey it makes request to /assertion/options of Janssen FIDO server.
- The response of
/assertion/options
contains the challenge and the allowCredentials field which contains a list of previously registered credentials. - The app requests the user for biometric input (thumb impression).
- One the user is verified, the authenticator finds a credential that matches the Relying Party ID and creates a new assertion by signing over the clientDataHash and authenticatorData with the private key generated for this account during enrolment.
- The app then make request to /assertion/result of Janssen FIDO server with authenticatorData and assertion signature.
- The FIDO server performs validation and responds with success or failure response. This request is made through Authorization Challenge Endpoint script so that authorization code is sent on success of
/assertion/result
request. - & 8. Using the authorization code, the app exchanges an access token and then user-info from Janssen Auth server.
How to obtain a normal OAuth token, and DPoP access tokens--requires token verifier to validate htm
and htu
against request.
Build either an iOS or Android app that authenticates against a local Jans install.