# Authentication and authorization for IDAC-PL

**URL:** <https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602>\
**Category:** Independent Data Access Centers\
**Created:** [February 17, 2026, 3:42pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602 "2026-02-17T15:42:06Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [February 17, 2026, 3:42pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/1 "2026-02-17T15:42:06Z")

</div>

We would like to test (and migrate) to central authorization/authentication for polish IDAC. Our current setup uses keycloak which uses github (specific organization) as IDP. As far as I understand we would need client secret and configuration created at USDAC. Details from our side are the following (please let us know if we missed anything):

- Production site:
  - Short name: IDAC-PL
  - Redirect URL: [https://rsp.cis.gov.pl/login](https://rsp.cis.gov.pl/login)

- Development site:
  - Short name: IDAC-PL-DEV
  - Redirect URL: [https://rsp2.cis.gov.pl/login](https://rsp2.cis.gov.pl/login)

Following suggestion from Knuth - tagging @rra and @frossie . Would you find some time to help here 🙂 ?

---

<div class="post-metadata">

**Author:** ![rra](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rra/32/978_2.png) [@rra](https://www.rubin.community/u/rra)\
**Post date:** [February 23, 2026, 10:30pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/2 "2026-02-23T22:30:57Z")

</div>

These OIDC clients have been set up but are not yet activated yet, since at present we only add new OIDC clients during our weekly maintenance window. I will set them up next Thursday during our patch window and then will message you a URL where you can get the client IDs and secrets to use on your end.

---

<div class="post-metadata">

**Author:** ![rra](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rra/32/978_2.png) [@rra](https://www.rubin.community/u/rra)\
**Post date:** [February 26, 2026, 11:25pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/3 "2026-02-26T23:25:35Z")

</div>

This has been set up and I sent you the credentials via DM.

---

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [March 3, 2026, 1:45pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/4 "2026-03-03T13:45:43Z")

</div>

Hi, thanks for creds, copying went OK. I’ll should be able to test this before end of the week, I’ll let you know

---

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [March 5, 2026, 2:53pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/5 "2026-03-05T14:53:59Z")

</div>

@rra - could you change the redirects to

> [https://rsp.cis.gov.pl/keycloak/realms/rsp/broker/data-lsst-cloud/endpoint](https://rsp.cis.gov.pl/keycloak/realms/rsp/broker/data-lsst-cloud/endpoint)

(for the production site) and

> [https://rsp2.cis.gov.pl/keycloak/realms/rsp/broker/data-lsst-cloud/endpoint](https://rsp2.cis.gov.pl/keycloak/realms/rsp/broker/data-lsst-cloud/endpoint) # devel site

(for the development site)?

Apparently my mind went on autopilot while writing the original request 😃

---

<div class="post-metadata">

**Author:** ![rra](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rra/32/978_2.png) [@rra](https://www.rubin.community/u/rra)\
**Post date:** [March 19, 2026, 10:17pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/6 "2026-03-19T22:17:37Z")

</div>

This should now be updated. Let us know if you have any problems.

---

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [March 23, 2026, 4:28pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/7 "2026-03-23T16:28:44Z")

</div>

Thanks ! This helped, things got further this time :). I have one minor issue - in the token the actuall issuer is

“iss”:“[https://data.lsst.cloud/](https://data.lsst.cloud/)”

while in [https://data.lsst.cloud/.well-known/openid-configuration](https://data.lsst.cloud/.well-known/openid-configuration) the “issuer” field lacks tha trailing “/”. This results in the following error in keycloak:

2026-03-23 10:16:07,183 ERROR [org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider] (executor-thread-1) Failed to make identity provider oauth callback: org.keycloak.broker.provider.IdentityBrokerException: Wrong issuer from token. Got: [https://data.lsst.cloud/](https://data.lsst.cloud/) expected: [https://data.lsst.cloud](https://data.lsst.cloud)

Unfortunatelly it seems once the external idp is configured in keycloak (at least via .well-known endpoint) it is not possible to change the issuer field (keycloak UI gives the possibility, but it seems it is not having any effect). For now correct way is to configure the idp in keycloak by hand (ie without using well-known for automatic configuration), with correct issuer from start. In longer run - would you be able to make entry in .well-known/openid-configuration consistent with the one in token?

For another thing I’m not exactly sure if it is another keycloak problem or bug on our side (understood as rsp stack - most likely in gafaelfawr - and not this specific deployment) . After workarounding the issuer problem I get the following error visible in keycloak logs:

2026-03-23 10:27:21,735 ERROR [org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider] (executor-thread-6) Failed to make identity provider oauth callback: org.keycloak.broker.provider.IdentityBrokerException: Could not fetch attributes from userinfo endpoint.

(…)  
Caused by: java.lang.IllegalArgumentException: Last unit does not have enough valid bits  
at java.base/java.util.Base64$Decoder.decode0(Base64.java:872)  
(…)

I saw this earlier while debugging the first issue - at least one part of the “id\_token” does not contain base64 padding. Please compare the results of:

echo eyJhbGciOiJSUzI1NiIsImtpZCI6ImdhZmFlbGZhd3IiLCJ0eXAiOiJKV1QifQ | base64 -d # the actual part of the token  
 → {“alg”:“RS256”,“kid”:“gafaelfawr”,“typ”:“JWT”}base64: invalid input

and

echo eyJhbGciOiJSUzI1NiIsImtpZCI6ImdhZmFlbGZhd3IiLCJ0eXAiOiJKV1QifQ== | base64 -d # padding added manually  
 → (proper decode, without base64 warning message)

Do you happen to know if openid standard requires padding to be present? This determines if I should open a keycloak issue or this should be fixed on rsp stack side

---

<div class="post-metadata">

**Author:** ![rra](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rra/32/978_2.png) [@rra](https://www.rubin.community/u/rra)\
**Post date:** [March 23, 2026, 7:12pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/8 "2026-03-23T19:12:54Z")

</div>

Hi Tomasz,

The first problem (the mismatch of issuer because of the trailing slash) is definitely a bug. I’ve found the problem and it should be fixed in our Thursday maintenance window this week.

For the second, could you double-check that the error is coming from decoding the id token? JWT requires use of base64url encoding, which prohibits adding padding, so it would be weird if a major implementation such as Keycloak were complaining about that. See:

[https://www.rfc-editor.org/rfc/rfc7515.html#section-2](https://www.rfc-editor.org/rfc/rfc7515.html#section-2)

under Base64url Encoding. I suspect it’s complaining about some other part of the userinfo response, but I’m not sure what it might be complaining about. Although, that said, I’m not sure what else it might be trying to decode, since the other values returned from the userinfo endpoint are not base64-encoded.

---

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [April 2, 2026, 7:22pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/9 "2026-04-02T19:22:57Z")

</div>

Hi Russ,

I managed to further debug the problem. Prior to the error, a call is made to `/auth/openid/token`. In response we get

> ```
> {"access_token":"AA-BBBBBBBB-CCCCCCCCCCCCC.ZZZZZZZZZZZZZZZZZZZZZZ","id_token": "(....)","expires_in":1191489,"scope":"openid profile","token_type":"Bearer"}
> 
> ```

keycloak then splits the access\_token using “.” as delimeter and tries to base64Url.decode the first part (i.e. “AA-BBBBBBBB-CCCCCCCCCCCCC”), which leads to the error message from previous post.

I’m having trouble interpreting this (as my openid experience is limited). In your opinion - is the base64 decoding of the first part of access\_token something it should try to perform or this operation makes completly no sense?

As final info - If I try decoding the part before the dot in python (using base64.urlsafe\_b64decode() method) I get the following error message:

> ```
> binascii.Error: Invalid base64-encoded string: number of data characters (25) cannot be 1 more than a multiple of 4
> 
> ```

---

<div class="post-metadata">

**Author:** ![rra](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rra/32/978_2.png) [@rra](https://www.rubin.community/u/rra)\
**Post date:** [April 2, 2026, 9:55pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/10 "2026-04-02T21:55:40Z")

</div>

It does need to split it apart in that way and decode the first part. The part before the period is the JOSE header, which it needs to decode to understand how to decode the rest.

It appears to be using the wrong base64 decoding algorithm because it’s expecting padding, which is prohibited in JWTs. I’m baffled by why it is handling this incorrectly, but you can verify that the token decodes correctly by pasting it into [https://www.jwt.io/](https://www.jwt.io/) (this will leak your username and full name to that web site, if you care).

Python weirdly does not provide an out-of-the-box function for decoding base64url encoding (unfortunately, this is not the same thing as urlsafe\_b64decode). The supported approach seems to be to manually add the padding. For example, from the [PyJWT source](https://github.com/jpadilla/pyjwt):

```auto
def base64url_decode(input: Union[bytes, str]) -> bytes:
    input_bytes = force_bytes(input)

    rem = len(input_bytes) % 4

    if rem > 0:
        input_bytes += b"=" * (4 - rem)

    return base64.urlsafe_b64decode(input_bytes)

```

---

<div class="post-metadata">

**Author:** ![rra](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rra/32/978_2.png) [@rra](https://www.rubin.community/u/rra)\
**Post date:** [April 2, 2026, 9:57pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/11 "2026-04-02T21:57:32Z")

</div>

Oh, or also in Python you could use [base64url · PyPI](https://pypi.org/project/base64url/)

---

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [April 7, 2026, 1:08pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/12 "2026-04-07T13:08:59Z")

</div>

Hmmm… Should the `access_id` field from `/auth/openid/token` response be a JWT token? I’m getting here data with only two fields (i.e. a single dot), as far as I (naively) understand there should be three of them in case of JWT.

BTW do you happen to know if any of IDACs has a working keycloak setup with central auth service? If the `access_id` is ok, it is likely some misconfiguration on my side.

For completeness - I tried running the above code snippet on the first field of `access_id` (i.e. part before the dot, `data` variable in code) :

```auto
import base64
from typing import Union

data = b'....'

def force_bytes(value: Union[bytes, str]) -> bytes:
    if isinstance(value, str):
        return value.encode("utf-8")
    elif isinstance(value, bytes):
        return value
    else:
        raise TypeError("Expected a string value")

def base64url_decode(input: Union[bytes, str]) -> bytes:
    input_bytes = force_bytes(input)

    rem = len(input_bytes) % 4

    if rem > 0:
        input_bytes += b"=" * (4 - rem)

    return base64.urlsafe_b64decode(input_bytes)

print(base64url_decode(data))

```

but this leads to the same error I posted above:

```auto
Traceback (most recent call last):
  File "/home/tfruboes/work_2026_1/2026.03.buildKeycloak/keycloak/dec.py", line 32, in <module>
    print(base64url_decode(data))
          ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/tfruboes/work_2026_1/2026.03.buildKeycloak/keycloak/dec.py", line 28, in base64url_decode
    return base64.urlsafe_b64decode(input_bytes)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/tfruboes/.pyenv/versions/3.12.11/lib/python3.12/base64.py", line 134, in urlsafe_b64decode
    return b64decode(s)
           ^^^^^^^^^^^^
  File "/home/tfruboes/.pyenv/versions/3.12.11/lib/python3.12/base64.py", line 88, in b64decode
    return binascii.a2b_base64(s, strict_mode=validate)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
binascii.Error: Invalid base64-encoded string: number of data characters (25) cannot be 1 more than a multiple of 4

```

When it comes to [jwt.io](http://jwt.io) - it also complains about not having three fields.

---

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [April 7, 2026, 2:05pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/13 "2026-04-07T14:05:40Z")

</div>

OK, so I further debugged keycloak. It has a promising setting of “Access Token is JWT” (`isAccessTokenJWT` when dumping realm config to json) which should control how acsess token is treated. Unfortunately this one is completely useless as there is an override hardcoded:

> <https://github.com/keycloak/keycloak/blob/1abce3ac8b80f9b3a152da503517468c6b60f6d1/services/src/main/java/org/keycloak/broker/oidc/KeycloakOIDCIdentityProvider.java#L55>

if I run keycloak with this line commented things get to proceed (to the moment where it crashes when writing to ldap due to missing mappers config).

So - the question is if the `access_token` (from `/auth/openid/token` path response in gafaelfawr) should always be a JWT token (I would guess the answer is no, but once again - I lack experience here 🙂 ).

For now on I’ll continue working with patched keycloak image (i.e. accepting `access_token` as it is currently).

— Edit  
After some digging - it seems, that access token is not required to be a JWT ([Final: OpenID Connect Core 1.0 incorporating errata set 2](https://openid.net/specs/openid-connect-core-1_0.html)). The override shown above looks like a development artifact, as it was included in the same commit as said configuration options ([Fix issue with access tokens claims not being imported using OIDC IDP… · keycloak/keycloak@a8bca52 · GitHub](https://github.com/keycloak/keycloak/commit/a8bca522c1a378eee8de0c82ce2f7d13c3622265))

---

<div class="post-metadata">

**Author:** ![rra](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/rra/32/978_2.png) [@rra](https://www.rubin.community/u/rra)\
**Post date:** [April 7, 2026, 9:48pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/14 "2026-04-07T21:48:06Z")

</div>

Ah, that makes more sense. Yes, indeed, `access_id` in our environment is an opaque token, not a JWT. It is not base64-encoded. Hopefully that Keycloak bug can be fixed.

---

<div class="post-metadata">

**Author:** ![Tomasz](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/tomasz/32/4015_2.png) [@Tomasz](https://www.rubin.community/u/Tomasz)\
**Post date:** [April 8, 2026, 1:28pm UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/15 "2026-04-08T13:28:53Z")

</div>

I made a PR allready ([Disable configuration override forcing access token to be of JWT type by fruboes · Pull Request #47826 · keycloak/keycloak · GitHub](https://github.com/keycloak/keycloak/pull/47826) ), fix seems to be trivial. Lets see if they merge this sometime soon

BTW are there plans/possibilities to extend set of parameters returned by lsst auth endpoint (i.e. as documented in [Configuring OpenID Connect — Gafaelfawr](https://gafaelfawr.lsst.io/user-guide/openid-connect.html) )? At this point a numerical identifier may be convenient for some IDACs, so uidNumber/gidNumber ldap attributes could be easily populated on user first IDAC login.

Notes:

- having a running ldap instance is enforced by gafaelfawr’ logic when setup involves keycloak (or similar)
- automatic uidNumber generation AFAIU is not supported by openldap (other servers likely the same)
- there is also a matter of uid range - we dont want the numbers to be of too low value in order not to mix with typical system uids (in my case there are also other range considerations but I would rather talk about them during our meetings and not write them down here)
- Finally - I think [GitHub - barche/keycloak-ldap-posixaccount · GitHub](https://github.com/barche/keycloak-ldap-posixaccount) could be a basis for a solution if numeric uid cannot be added to our openid response for some reason. But this may mean we would need to maintain our own keycloak image builds (as keycloak version is set during the plugin build; I dont know how problematic is version mismatch)

---

<div class="post-metadata">

**Author:** ![gpfrancis](https://sea2.discourse-cdn.com/flex002/user_avatar/www.rubin.community/gpfrancis/32/1889_2.png) [@gpfrancis](https://www.rubin.community/u/gpfrancis)\
**Post date:** [April 9, 2026, 10:02am UTC](https://www.rubin.community/t/authentication-and-authorization-for-idac-pl/11602/16 "2026-04-09T10:02:15Z")

</div>

Regarding the uid/gid issue, the approach that I am going with for now for the UKIDAC is to create new users with a uid of -1 and run a minimal service that simply looks for those users and assigns a real uid and gid. The code is here: [https://github.com/lsst-uk/aai-proxy/blob/main/uidset/uidset.py](https://github.com/lsst-uk/aai-proxy/blob/main/uidset/uidset.py) As you note, a keycloak plugin could also do the job, but with all the downsides that you mention.

Clearly for systems where the ldap is only used for the RSP and isn’t trying to integrate with anything else, getting the uid and gid from the IDP as you suggest would be the cleanest solution.
