-
Notifications
You must be signed in to change notification settings - Fork 80
DPoP Mobile App POC
a. On the client registration (DCR) screen user enters the OpenID Provider Configuration URL and scope.
b. On click of the Register
button the app fetches OpenID Provider configuration using URL and stores it in SQLite database table of android.
The app extracts registration_endpoint
from OpenID Provider configuration and requests for DCR with attestation.
------------
Request
------------
curl -X POST -k -H 'Content-Type: application/json' -i 'https://admin-ui-test.gluu.org/jans-auth/restv1/register' --data '{
"application_type":"web",
"client_name":"DPoPAppClient-bc041d99-2c02-4622-8b6b",
"evidence":"eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7ImUiOiJBUUFCIiwia3R5IjoiUlNBIiwibiI6IjNwMmN1aXNjOFJ3U0VYN1dEYUxUamlQRUJ1bVZnTlIzVm96MnBobGh0aDV3Y2R4aGZ3aFpUcFRvOHJUWFBSbWozUWM5ck1jOGo5djM5MWZKbXhmSWpWM2Q0YUJVZm5aOS00VFJzdmlXVEJIN2RkODBtWTZhcnl5OTBaY0ZmTHdNektzSG1ITHJfTENJUjNKZ3F1MG1TTm9EUHFjTmNFcVVPZVZxVTV2YnRXUHJMdVNlMEJTNmxaRDQ2aXZBSWttOUJhb2xqT1NEcGJvV2gtUW5nMzBVQTJhZnhHN05JVjlwV1Y2S2hka0h1dUtDUXN1RlRpa2Z6cGlWQVRaLTlFcllUU1hOMDVqT0RJUk5Mc1FnV0NyUnBiMEdheGlick5OWTZmcWF2dkgycDJGaXlnbEFaUnBqTDhRNkVWd0Noek9uT1BySkpDZXdCdTdHVFZ4dVZuaHc0dyJ9fQ.eyJhYXBOYW1lIjoiRFBvUEFwcCIsImlhdCI6MTY5MzU2OTQ0ODUwMywic2VxIjoiYzlmMWFhOTUtNGZhNi00NGQ4LTljNTYtYzhkNDcwNGJlMTQyIiwianRpIjoiZWRlYWQxOWQtYzQ1Yy00NDVhLWFlN2ItZTM2NjRiOTBhY2ZjIn0.OQhT-lzYIUWRb4YV4tZNHHTOKAZOax8yZW3HONxLNIvUsxTeS7zB55G5M8WmdwVA4UTcRL6oBj_j-Ep_r6X1fx9ZaJ-SmGCONgC8LxHPmWJCb1eQxYq-7S-CWTtS-SCK4FW473Kg-Kk_FSlyy5tFbH5p_x_CTiPuTgWK5Ct9OwbJ9tyaaiqeXoRgBUEjjjElSYoZqutFbe1WmKrlwblVtXc47JzaZBbnDt3Goukz1HUln_xL0sT_CnxaTVLKdAT7IIfK5UuVIEiKvoqathMdKlqynrn9kyLXwflpMWbirWrQxIpIbkQ6srHStyDDh1zBEyYNAj-pXz9iyhHULoz0Ig",
"grant_types":["authorization_code"],
"jwks":"{\"keys\":[{\"e\":\"AQAB\",\"kty\":\"RSA\",\"n\":\"pzVIV71wHi1fG3TEcCUJw0uolOBUryEJPy8IFpI20lAWqWw5prPn2mPqsyaOPpQtNX2_12PmZjlDq3SjInipSK_saSJ4pm-LCTOYZm55n5QbiK-iCR0DgCVlAeNj6YIenk1Tdy0KSuYoZxOL7iOdMAT9f7qvRAlSdWivOef_tDEtCIbZ3aKoNujv0xPUmOgnZ0U1QdxK3bmprV08O6dV6-_GJBeEdGZ5qZezPIxyjaxiGcoDk47QxdFz-aD38md-zQDEr9toU08j08bgeZLvbVr5e_M-fzhGY5yEISg1e-87n_v3HbdKFGuRFqYp3CYVayuYMWJsIIq8aEPZxdi8qw\"}]}",
"redirect_uris":["https://admin-ui-test.gluu.org"],
"response_types":["code"],
"scope":"openid"
}'
------------
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://admin-ui-test.gluu.org/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://admin-ui-test.gluu.org"],
"redirect_uris_regex": "",
"additional_audience": [],
"frontchannel_logout_session_required": false,
"client_secret_expires_at": 0,
"access_token_signing_alg": "RS256",
"response_types": ["code"]
}
a. Once DCR is successful the app save OIDC client details in SqlLite DB. Every time the user opens the app, it check if the client details are present in DB. If yes, then it directly forwards to Login page asking for username/password.
b. On submitting username/password the app extracts authorization_challenge_endpoint
from the OpenID Provider configuration and requests to get the Authorization Code.
------------
Request
------------
curl -k https://admin-ui-test.gluu.org/jans-auth/restv1/authorization_challenge -d 'grant_type=authorization_code' -d 'scope=openid' -d 'username=admin' -d 'password=secret' -d 'state=0x74ab847000' -d 'nonce=8974ab847000' -d 'client_id=05fd2650-8478-4bca-9488-b14f7219473b'
------------
Response
------------
{"authorization_code":"cdf09c4a-10f4-467e-9f6f-a697db44b108"}
The app extracts token_endpoint
from the OpenID Provider configuration and requests to get the access_token.
------------
Request
------------
curl -k -u '05fd2650-8478-4bca-9488-b14f7219473b:97c734ca-a729-49b7-9ec3-514e43ba530b' -H 'DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7ImUiOiJBUUFCIiwia3R5IjoiUlNBIiwibiI6IjNwMmN1aXNjOFJ3U0VYN1dEYUxUamlQRUJ1bVZnTlIzVm96MnBobGh0aDV3Y2R4aGZ3aFpUcFRvOHJUWFBSbWozUWM5ck1jOGo5djM5MWZKbXhmSWpWM2Q0YUJVZm5aOS00VFJzdmlXVEJIN2RkODBtWTZhcnl5OTBaY0ZmTHdNektzSG1ITHJfTENJUjNKZ3F1MG1TTm9EUHFjTmNFcVVPZVZxVTV2YnRXUHJMdVNlMEJTNmxaRDQ2aXZBSWttOUJhb2xqT1NEcGJvV2gtUW5nMzBVQTJhZnhHN05JVjlwV1Y2S2hka0h1dUtDUXN1RlRpa2Z6cGlWQVRaLTlFcllUU1hOMDVqT0RJUk5Mc1FnV0NyUnBiMEdheGlick5OWTZmcWF2dkgycDJGaXlnbEFaUnBqTDhRNkVWd0Noek9uT1BySkpDZXdCdTdHVFZ4dVZuaHc0dyJ9fQ.eyJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9hZG1pbi11aS10ZXN0LmdsdXUub3JnIiwiaWF0IjoxNjkzNTY5NDg0NTQ0LCJqdGkiOiI1MWY0ZWRkYy00MzZjLTRjMmQtYmU1OS1mZjkzNTNiNDI0OTQifQ.MLCDkwyaWVV5kiowWJdnvT241zL0UwMrZ5Kes-uQ_12tKROC0BSZkf2PQ08PcA9nGEw5Ab4MPJOOQlLZAXqkiI7W2zx9BjLIWnRkkSkCS3ucRIfJWxvuQ4W1bfbtUvy9UTZ3UZSD4pxdsZSoGRADePH6JEJy4GkWH6qMrCHeLr2YEjeaBPzJ3Z4YazX8p7kt7_dbNz56hU78hiqu9JetM0-9_5CLqxbomsc8KzreWZ-Mazt_iJJHp_pEKZouClbieKsI_lWfko7MyzxIZNJm6FKdMtCi8SWsXRnuLUkNES0TBe61-yJjqRFqJGZ9BOmwIo8txkmuFHqd403ibaPiiw' https://admin-ui-test.gluu.org/jans-auth/restv1/token -d 'grant_type=authorization_code' -d 'scope=openid' -d 'code=c13327d9-9a1c-41f7-8d3c-06d83ee7f69f' -d 'redirect_uri=https://admin-ui-test.gluu.org/callback'
------------
Response
------------
{"access_token":"fb49e7e7-2831-4dfd-8947-30ea2c6f305e","scope":"openid","id_token":"eyJraWQiOiJjb25uZWN0X2E4MWQyZWIzLTY2YTYtNGEzOS1hN2I2LTEzODBiMzAzYTYwNl9zaWdfcnMyNTYiLCJ0eXAiOiJqd3QiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiTG5ocnFjR0ZiYmw1X3ZCaG1Yanc1ZyIsInN1YiI6IkxVS0RHR0Q3aXQtb3lqUFE3akV6RV90WF9IZVVvcVRjeU1weTNNZ0ZIa0EiLCJhbXIiOltdLCJpc3MiOiJodHRwczovL2FkbWluLXVpLXRlc3QuZ2x1dS5vcmciLCJub25jZSI6Ijg5NzRhYjg0NzAwMCIsImphbnNPcGVuSURDb25uZWN0VmVyc2lvbiI6Im9wZW5pZGNvbm5lY3QtMS4wIiwiYXVkIjoiMDVmZDI2NTAtODQ3OC00YmNhLTk0ODgtYjE0ZjcyMTk0NzNiIiwicmFuZG9tIjoiMDg4ZmQ5MTUtNDA5NC00NDgxLTlkODEtZTllZDdhMTY3MGE3IiwiYWNyIjoiZGVmYXVsdF9jaGFsbGVuZ2UiLCJjX2hhc2giOiJjZmJ0d0ZWek51QzhpVDFFQWtJdGlnIiwiYXV0aF90aW1lIjoxNjkzNTc0Mzg0LCJleHAiOjE2OTM1NzgwMTgsImdyYW50IjoiYXV0aG9yaXphdGlvbl9jb2RlIiwiaWF0IjoxNjkzNTc0NDE4fQ.ODhYZTdC0IJjidUAMyVbRKKoovyW1-2AdzVPtn6tx232Vjx6Mxs-Sng57YV6lUdjFLbYfmUjn5JM90Zg3buJHpu6gZKaLs_44j-1i9NbJrAFhe_6libXO0Bib4v5vacYx_0zllXO5FklDdvctahxFc9-xG8pTolkqEGJGjILyNI70NOjodZxBTPPZDBSER9MnD0V_CmRM0izonroV_HyvWDCbTJm9sjBufoY2UkpKCYpyKytu5zSUFq6gq3DEX661Vx_ANgpzy_0BkJgfQ4-juvVPoBdcQnqK7akpwgqyf82NK-pFSZXdduO1Z343L_uYyzzurEkMHf6s_8jre4EXw","token_type":"DPoP","expires_in":299}
The app extracts userinfo_endpoint
from the OpenID Provider configuration and requests to user-info.
------------
Request
------------
curl -k -H 'Authorization=Bearer fb49e7e7-2831-4dfd-8947-30ea2c6f305e' https://admin-ui-test.gluu.org/jans-auth/restv1/userinfo -d 'access_token=fb49e7e7-2831-4dfd-8947-30ea2c6f305e'
------------
Response
------------
{"sub":"LUKDGGD7it-oyjPQ7jEzE_tX_HeUoqTcyMpy3MgFHkA"}
The access token is revoked in the logout process.
**References: ** https://github.com/JanssenProject/jans/wiki/Mobile-DPoP-FIDO-Authn
-
Using BiometricPrompt which provides a consistent user interface to fingerprint registration/authentication.
-
Using Authenticator : https://github.com/duo-labs/android-webauthn-authenticator/tree/master
Reference:
https://developers.yubico.com/WebAuthn/WebAuthn_Developer_Guide/WebAuthn_Client_Registration.html
https://webauthn.guide/#registration
title WebAuthn Registration Flow for Native App
actor User
User->Android App: submit username, \njans-fido configuration url
Android App-> Android App: save following urls from jans-fido configuration into Mobile database\n1. /attestation/options\n2. /attestation/result\n 3. /assertion/options\n4. /assertion/result
opt registration
Android App-> Android App: 1.show biometric prompt requesting fingerprint\n2. On successful enrolment generate asymetric key pair in android keystore
Android App->jans-fido: POST /attestation/options \n { "username": "admin",\n "displayName": "admin",\n "attestation": "none"}
jans-fido->Android App: PublicKeyCredentialCreationOptions:\n {"attestation": "none",\n "authenticatorSelection": {},\n "challenge": "vr27LUiJZF2CN4AncVTsAWlJzAVNsofcr8zM3Ej2Dk8",\n "pubKeyCredParams": [...],\n "rp": {...},\n "user": {...}}
Android App->Android App: generate attestationObject from authenticator using /attestation/options response
Android App->Android App: generate ClientDataJSON and ClientDataHash using challenge, type: webauthn.create and origin (jans-fido host)
Android App->jans-fido: POST /attestation/result \n {"id": "bas64 encoded attestationObject.getCredentialId() ...",\n"type": "public-key",\n "response": {\n"attestationObject": "base64url encoded attestationObject",\n "clientDataJSON": "base64url encoded clientDataJSON"\n }}
jans-fido->Android App: {createdCredentials={type=public-key, id=BS7CHyycngx9H3D8oZQ2sohKBsEDkQ_yoJTClWwR95Y=}, \nstatus=ok, errorMessage=}
end
opt authentication
Android App-> Android App: 1.show biometric prompt requesting fingerprint\n2. On successful capturing of fingerprint generate asymetric key pair\n and match with key pair stored during enrolment
Android App->jans-fido: POST /assertion/options\n{"username": "admin"}
jans-fido->Android App:AssertionOptionResponse\n{challenge='XCijJZZqvUPHf-SEuMID5Ef9lP5jcsG3A6blPtGy7e0',\n user='null',\n userVerification='preferred', \nrpId='admin-ui-test.gluu.org', \nstatus='ok',\n errorMessage='', \nallowCredentials=[...]}
Android App-> Android App:generate ClientDataJSON and ClientDataHash using challenge, type: webauthn.get and origin (jans-fido host)
Android App-> Android App: get assertionObject from authenticator using above response and clientDataHash
Android App->jans-fido: POST /assertion/result\n{"id": "base64 encoded assertionObject.CredentialId",\n "type":"public-key",\n "rawId": "base64 encoded assertionObject.CredentialId",\n "response":{"clientDataJSON": "bas64 encoded ClientDataJSON", \n"authenticatorData": "base64 encoded assertionObject.authenticatorData",\n "signature": "base64 encoded assertionObject.signature"\n}}
jans-fido->Android App: {authenticatedCredentials={type=public-key, id=UIIoHYAJygJgfBJeSloipjLT34AHznSAuDZyj75aPMs=}, status=ok, errorMessage=, username=admin}
end